3

簡略化された表:

CREATE TABLE products (
product_no integer PRIMARY KEY,
sales integer,
status varchar(16),
category varchar(16));

CREATE INDEX index_products_sales ON products (sales);
CREATE INDEX index_products_status ON products (status);
CREATE INDEX index_products_category ON products (category);

PostgreSQLのバージョンは8.4です。列「ステータス」および「カテゴリ」

15のカテゴリにまたがる2,000万の製品/行があります。

最もよく使用されるクエリの1つは、カテゴリ「cat3」および「cat7」の製品を除く、最も売れた3つの製品を取得することです。

SELECT product_no, sales 
FROM products 
WHERE status = 'something' AND category NOT IN ('cat3', 'cat7') 
ORDER BY sales DESC 
LIMIT 3;

Limit  (cost=0.00..8833.39 rows=3 width=12) (actual time=9235.332..9356.284 rows=3 loops=1)
   ->  Index Scan using index_products_sales on products  (cost=0.00..68935806.85 rows=23412 width=12) (actual time=9235.327..9356.278 rows=3 loops=1)
     Filter: (((category)::text <> ALL ('{cat3,cat7}'::text[])) AND ((status)::text = 'something'::text))

この特定のクエリをより高速に実行するための最良のインデックスは何でしょうか?

4

2 に答える 2

13

この特定の並べ替え順序で、部分的な複数列のインデックスを作成します。

CREATE INDEX products_status_sales_partial_idx ON products (status, sales DESC)
WHERE  category NOT IN ('cat3','cat7');

クエリを少し変更します。

SELECT product_no, sales 
FROM   products 
WHERE  status = 'something'
AND    category NOT IN ('cat3', 'cat7') 
ORDER  BY status, sales DESC 
LIMIT  3;

status句の最初の要素として追加することは、ORDER BY冗長で無意味に思えます。しかし、試してみてください。

なんで?

クエリ プランナーは理解できるほど賢くありません。

WHERE  status = 'something' ...
ORDER  BY sales DESC

(status, sales DESC)論理的な結果として、インデックスの並べ替え順序が一致します。したがって、該当するすべての行を読み取り、並べ替えて上位 3 行を選択します。

に追加statusするORDER BYことで、クエリ プランナーがインデックスから上位 3 つのエントリを直接読み取ることができるようになります。桁違いのスピードアップが期待できます。

PostgreSQL 8.4 および 9.1 でテスト済み。

于 2012-07-22T02:49:17.303 に答える
2

B ツリー インデックスは依然として最善の策だと思います。でも、私は間違っているかもしれません。2つのことをテストすると思います。

まず、「cat3」と「cat7」を除外したカテゴリの部分インデックス。

CREATE INDEX index_products_category ON products (category)
  WHERE category NOT IN ('cat3','cat7');

2 つ目は、売上の降順の並べ替えです。

CREATE INDEX index_products_sales ON products (sales DESC);

ただし、これらのいずれかが他のクエリの速度を低下させる可能性があるため、既存のインデックスに加えて、これらのいずれかまたは両方が必要になる場合があります。

于 2012-06-21T12:50:25.650 に答える