1
SELECT * FROM table1
WHERE (col1, col2) IN (($1, $2), ($3, $4))
ORDER  BY col3
LIMIT  10;

の出力EXPLAIN ANALYZE:

 Limit  (cost=59174.75..59174.77 rows=10 width=113) (actual time=3632.627..3632.661 rows=10 loops=1)
   ->  Sort  (cost=59174.75..59180.22 rows=2188 width=113) (actual time=3632.623..3632.634 rows=10 loops=1)
         Sort Key: col3
         Sort Method: top-N heapsort  Memory: 27kB
         ->  Nested Loop  (cost=2.62..59127.46 rows=2188 width=113) (actual time=0.234..3561.309 rows=38347 loops=1)
   ...........
   Total runtime: 3632.818 ms

しかし、注文を削除すると:

SELECT * FROM table1 WHERE (col1, col2) IN (($1, $2), ($3, $4)) LIMIT 10;
 Limit  (cost=2.62..272.85 rows=10 width=105) (actual time=0.258..1.143 rows=10 loops=1)
   ->  Nested Loop  (cost=2.62..59127.46 rows=2188 width=105) (actual time=0.255..1.115 rows=10 loops=1)
........
Total runtime: 1.306 ms
  1. コンポジットbtree index on (col1, col2)と がありbtree index on col3ます。
  2. 書き込みパフォーマンスとストレージは優先事項ではありません。読み取りパフォーマンスは最も重要であり、可能な限り高速である必要があります。
  3. これは、IN 句を使用したクエリをサポートできる必要があります: WHERE (col1, col2) IN (($1, $2), ($3, $4)) ORDER BY col3 LIMIT 10;。(ルックアップは常に IN 句を使用してから順序付けます。)

注: (col1、col2、col3) にインデックスを作成することは可能ですか? それは使用(col1, col2)して検索し、col3すでに注文しています...

4

1 に答える 1

2

はい。あなたはすでに質問で答えを得ています。
指定されたクエリでは、複数列のインデックス(col1, col2, col3)最適です。やってみなよ。

複数列 B ツリー インデックスの列の順序の詳細については、dba.SE に関するこの関連する質問:
最初のフィールドでのクエリにも複合インデックスは適していますか?

さらに、 のすべての列が実際に必要ない場合は、パフォーマンスを向上させるのではなくtable1、必要な列だけをSELECTリストに*入れます。

追加の要件について:

WHERE (col1, col2) IN (($1, $2), ($3, $4))

次と同等です。

WHERE (col1 = $1 AND col2 = $2 OR
       col1 = $3 AND col2 = $4)

(col1, col2, col3)Postgres は事前にソートされたリストをインデックスからフェッチすることができないため、これは に対するインデックスの有効性を低下させます。場合によります。リスト内のアイテムが少なくなりIN、同じcol3あたりの行(col1, col2)が多いほど、上記のインデックスからより多くを得ることができます。

テストする必要があります。さらにインデックスを作成し、サーバーが適切に構成されていること、統計が最新 ( ANALYZE) であること、およびコスト設定が適切であることを確認してからEXPLAIN、Postgres が選択したものを表示します。ユースケースを表す一連のクエリを必ず実行してください。最後に、使用されていないインデックスを削除します。

Postgres をだまして特別なインデックスを効果的に使用させる

ソートステップは高価な部分のようです。次の代替クエリを試してください:リストUNION ALL内のアイテムごとに 1 つのレッグ。INこれにより、Postgres は拒否できないというオファーが作成されます。特別なインデックスは、このクエリのレッグに完全に適合します。また、最終的なソート ステップは、わずかなIN品目に対して安価です。

(
SELECT *
FROM   table1
WHERE  col1 = $1 AND col2 = $3
ORDER  BY col3
LIMIT  10
)
UNION  ALL
(
SELECT *
FROM   table1
WHERE  col1 = $3 AND col2 = $4
ORDER  BY col3
LIMIT  10
)
... UNION  ALL ...
ORDER  BY col3
LIMIT  10

最後のandに加えて、各レグにORDER BYandを許可するには、すべての括弧が必要であることに注意してください。LIMITORDER BYLIMIT

于 2014-03-17T19:37:15.977 に答える