简化表格:
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。列“状态”和“类别”
共有2000种产品/行分布在15个类别中。
最常用的查询之一是获得三个销售最多的产品,不包括'cat3'和'cat7'类别的产品:
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))
使这个特定查询运行得更快的最佳索引是什么?
答案 0 :(得分: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进行测试。
答案 1 :(得分:2)
我认为b树索引仍然是你最好的选择。不过我可能错了。我想我会测试两件事。
首先,排除'cat3'和'cat7'的类别的部分索引。
CREATE INDEX index_products_category ON products (category)
WHERE category NOT IN ('cat3','cat7');
其次,销售额下降。
CREATE INDEX index_products_sales ON products (sales DESC);
其中任何一个都可能会减慢其他查询的速度,因此您可能需要其中一个或两个以及到现有索引。