比較的少ないと仮定します 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クエリを最適化して、ユーザーごとに最新の行を取得します