sql >> データベース >  >> RDS >> PostgreSQL

グループごとの最大クエリを最適化する

    比較的少ないと仮定します optionsの行 recordsの多くの行

    通常、ルックアップテーブルoptionsがあります records.option_idから参照されます 、理想的には外部キー制約付き。そうでない場合は、参照整合性を適用するために作成することをお勧めします:

    CREATE TABLE options (
      option_id int  PRIMARY KEY
    , option    text UNIQUE NOT NULL
    );
    
    INSERT INTO options
    SELECT DISTINCT option_id, 'option' || option_id -- dummy option names
    FROM   records;
    

    そうすれば、ルーズインデックススキャンをエミュレートする必要がなくなり、非常にシンプルかつ高速になります。 。相関するサブクエリでは、(option_id, id)のプレーンインデックスを使用できます 。

    SELECT option_id, (SELECT max(id)
                       FROM   records
                       WHERE  option_id = o.option_id) AS max_id
    FROM   options o
    ORDER  BY 1;
    

    これには、テーブルrecordsに一致しないオプションが含まれます 。 max_idに対してNULLを取得します 外側のSELECTでそのような行を簡単に削除できます 必要に応じて。

    または(同じ結果):

    SELECT option_id, (SELECT id
                       FROM   records
                       WHERE  option_id = o.option_id
                       ORDER  BY id DESC NULLS LAST
                       LIMIT  1) AS max_id
    FROM   options o
    ORDER  BY 1;
    

    少し速いかもしれません。サブクエリは、並べ替え順序DESC NULLS LASTを使用します -集計関数max()と同じ NULL値を無視します。 DESCだけを並べ替える 最初にNULLになります:

    • PostgreSQLクエリでDESCを注文するときにNULL値が最初に来るのはなぜですか?

    このための完璧なインデックス:

    CREATE INDEX on records (option_id, id DESC NULLS LAST);
    

    列が定義されている間は、インデックスの並べ替え順序はそれほど重要ではありませんNOT NULL

    小さなテーブルのoptionsを順次スキャンすることもできます 、これはすべての行をフェッチするための最速の方法です。 ORDER BY 事前にソートされた行をフェッチするために、インデックス(のみ)スキャンを取り込む場合があります。
    大きなテーブルrecords (ビットマップ)インデックススキャン、または可能であればインデックスのみのスキャンを介してのみアクセスされます 。

    db<>ここでフィドル -単純なケースの2つのインデックスのみのスキャンを表示
    Old sqlfiddle

    または LATERALを使用する Postgres 9.3以降で同様の効果を得るために参加します:

    • GROUP BYクエリを最適化して、ユーザーごとに最新の行を取得します


    1. GreenDAOは、テーブル間の複数の関係をサポートします

    2. MacにSQLOPSをインストールする方法

    3. 繰り返し可能な読み取り分離レベル

    4. LINQ to Entitiesは、メソッド'System.String ToString()'メソッドを認識せず、このメソッドをストア式に変換できません