ホームページ >データベース >mysql チュートリアル >各ユーザーの最新の行を効率的に取得するには、GROUP BY クエリを最適化するにはどうすればよいですか?

各ユーザーの最新の行を効率的に取得するには、GROUP BY クエリを最適化するにはどうすればよいですか?

DDD
DDDオリジナル
2025-01-24 00:37:14237ブラウズ

How Can I Optimize GROUP BY Queries to Efficiently Retrieve the Latest Row for Each User?

ユーザーごとに最新の行を取得するための GROUP BY クエリの最適化戦略

log_date、user_id、および payload として構造化されたユーザー メッセージを含むテーブルが与えられたとします。 、タスクは、特定のユーザーの前に各ユーザーの最新レコードを効率的に取得することです。 date.

複数列インデックス

読み取りパフォーマンスを向上させるには、user_id と log_date に複数列インデックスを作成します。

CREATE INDEX log_combo_idx ON log (user_id, log_date DESC NULLS LAST);

Index-カバーインデックスを使用してスキャンのみ

インデックスのみのスキャンでは、ペイロード列を含むカバー インデックスを定義します。

CREATE INDEX log_combo_covering_idx ON log (user_id, log_date DESC NULLS LAST) INCLUDE (payload);

SELECT DISTINCT ON()

小さいテーブルまたは user_id ごとに数行の場合、 SELECT DISTINCT ON() を使用すると、効率的:

SELECT DISTINCT ON(user_id) log_date, payload
FROM log
WHERE log_date <= :mydate
ORDER BY user_id, log_date DESC;

インデックス スキップ スキャン エミュレーション

user_id ごとに多くの行がある大規模なテーブルの場合は、LATERAL 結合を使用した再帰 CTE を使用してインデックス スキップ スキャンをエミュレートすることを検討してください。

WITH RECURSIVE cte AS (
   (
   SELECT user_id, log_date, payload
   FROM   log
   WHERE  log_date <= :mydate
   ORDER  BY user_id, log_date DESC NULLS LAST
   LIMIT  1
   )
   UNION ALL
   SELECT l.*
   FROM   cte c
   CROSS  JOIN LATERAL (
      SELECT l.user_id, l.log_date, l.payload
      FROM   log l
      WHERE  l.user_id > c.user_id  -- lateral reference
      AND    log_date <= :mydate    -- repeat condition
      ORDER  BY l.user_id, l.log_date DESC NULLS LAST
      LIMIT  1
      ) l
   )
TABLE  cte
ORDER  BY user_id;

ユーザーを分けるテーブル

別の users テーブルが存在する場合は、次のような単純化されたソリューションが可能です。

LATERAL Join

SELECT u.user_id, l.log_date, l.payload
FROM   users u
CROSS  JOIN LATERAL (
   SELECT l.log_date, l.payload
   FROM   log l
   WHERE  l.user_id = u.user_id         -- lateral reference
   AND    l.log_date <= :mydate
   ORDER  BY l.log_date DESC NULLS LAST
   LIMIT  1
   ) l;

相関サブクエリ

SELECT user_id, (combo1).*              -- note parentheses
FROM (
   SELECT u.user_id
        , (SELECT (l.log_date, l.payload)::combo
           FROM   log l
           WHERE  l.user_id = u.user_id
           AND    l.log_date <= :mydate
           ORDER  BY l.log_date DESC NULLS LAST
           LIMIT  1) AS combo1
   FROM   users u
   ) sub;

これら最適化では、インデックスの利用、スキップ スキャンのエミュレーション、ユーザー情報用の別のテーブルの利用により、クエリのパフォーマンスが向上します。

以上が各ユーザーの最新の行を効率的に取得するには、GROUP BY クエリを最適化するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。