Jim*_*Bob 11 postgresql performance index-tuning postgresql-performance
我已经读到 PostgreSQL 通常可以使用多个索引,但是在跨两个索引的查询的特定情况下,它会同时使用两个索引吗?如果是这样,它们是按顺序加载还是一起加载?
例如,如果此查询跨越两个部分索引 by column_1,将如何使用部分索引,以及如何加载和丢弃索引数据:
SELECT 1 FROM sample_table WHERE column_1 > 50 AND column_2 < 50000
Run Code Online (Sandbox Code Playgroud)
Cra*_*ger 17
非常简短的版本:是的,有时。
PostgreSQL 可以使用位图索引扫描来组合多个索引。
像这样的谓词
WHERE a > 50 AND a < 50000
Run Code Online (Sandbox Code Playgroud)
是更一般形式的特化:
wHERE a > 50 and b < 50000
Run Code Online (Sandbox Code Playgroud)
对于 a = b。
PostgreSQL 在这里可以使用两个索引,一个用于谓词的每个部分,然后对AND它们进行位图。如果它们碰巧位于同一列的不同范围内,则无关紧要。
这是很多比单一指标低效,并且可能不适合某些查询是有用的,但它是可能的。
更大的问题是PostgreSQL的部分索引支持不是很亮。不管是否有一个或两个索引,它可能根本不知道它可以使用该索引。
演示设置:
CREATE TABLE partial (x integer, y integer);
CREATE INDEX xs_above_50 ON partial(x) WHERE (x > 50);
CREATE INDEX xs_below_50000 ON partial(x) WHERE (x < 5000);
INSERT INTO partial(x,y) SELECT a, a FROM generate_series(1,100000) a;
Run Code Online (Sandbox Code Playgroud)
好的,对于给定的查询,Pg 会喜欢什么?
regress=> EXPLAIN SELECT y FROM partial WHERE x > 50 AND x < 50000;
QUERY PLAN
----------------------------------------------------------------------------------
Index Scan using xs_above_50 on partial (cost=0.29..1788.47 rows=50309 width=4)
Index Cond: ((x > 50) AND (x < 50000))
(2 rows)
regress=> EXPLAIN SELECT y FROM partial WHERE x > 20 AND x < 50000;
QUERY PLAN
--------------------------------------------------------------
Seq Scan on partial (cost=0.00..1943.00 rows=50339 width=4)
Filter: ((x > 20) AND (x < 50000))
(2 rows)
regress=> EXPLAIN SELECT y FROM partial WHERE x > 100 AND x < 50000;
QUERY PLAN
----------------------------------------------------------------------------------
Index Scan using xs_above_50 on partial (cost=0.29..1787.45 rows=50258 width=4)
Index Cond: ((x > 100) AND (x < 50000))
(2 rows)
regress=> EXPLAIN SELECT y FROM partial WHERE x > 100 AND x < 20000;
QUERY PLAN
---------------------------------------------------------------------------------
Index Scan using xs_above_50 on partial (cost=0.29..710.71 rows=19921 width=4)
Index Cond: ((x > 100) AND (x < 20000))
(2 rows)
Run Code Online (Sandbox Code Playgroud)
如果我们试图强制执行位图索引扫描只是为了找出 Pg 是否可以使用一个索引扫描,即使对于这种特殊的简单情况和小样本不值得这样做怎么办?
尝试:
regress=> SET enable_seqscan = off;
SET
regress=> SET enable_indexscan = off;
SET
regress=> SET enable_indexonlyscan = off;
SET
regress=> EXPLAIN SELECT y FROM partial WHERE x > 100 AND x < 20000;
QUERY PLAN
--------------------------------------------------------------------------------
Bitmap Heap Scan on partial (cost=424.48..1166.30 rows=19921 width=4)
Recheck Cond: ((x > 100) AND (x < 20000))
-> Bitmap Index Scan on xs_above_50 (cost=0.00..419.50 rows=19921 width=0)
Index Cond: ((x > 100) AND (x < 20000))
(4 rows)
Run Code Online (Sandbox Code Playgroud)
嗯。不。没有在那里组合索引。不过,它可能能够但根本不认为值得扫描第二个索引。
对两个谓词进行 OR 运算的查询呢?
regress=> EXPLAIN SELECT y FROM partial WHERE x > 100 OR x < 200;
QUERY PLAN
---------------------------------------------------------------------------------------
Bitmap Heap Scan on partial (cost=1905.29..3848.29 rows=99908 width=4)
Recheck Cond: ((x > 100) OR (x < 200))
-> BitmapOr (cost=1905.29..1905.29 rows=100000 width=0)
-> Bitmap Index Scan on xs_above_50 (cost=0.00..1849.60 rows=99908 width=0)
Index Cond: (x > 100)
-> Bitmap Index Scan on xs_below_50000 (cost=0.00..5.73 rows=193 width=0)
Index Cond: (x < 200)
(7 rows)
Run Code Online (Sandbox Code Playgroud)
在这里,PostgreSQL 对两个索引进行 OR 运算以找到匹配项,然后进行堆扫描并重新检查。
所以是的,PostgreSQL 可以组合多个部分索引,至少对于某些查询,这样做很有用。
但是,如果我RESET计划者覆盖...
regress=> RESET enable_seqscan;
RESET
regress=> RESET enable_indexscan ;
RESET
regress=> RESET enable_indexonlyscan ;
RESET
regress=> EXPLAIN SELECT y FROM partial WHERE x > 100 OR x < 200;
QUERY PLAN
--------------------------------------------------------------
Seq Scan on partial (cost=0.00..1943.00 rows=99908 width=4)
Filter: ((x > 100) OR (x < 200))
(2 rows)
Run Code Online (Sandbox Code Playgroud)
... Pg 会意识到顺序扫描表格会更快。
| 归档时间: |
|
| 查看次数: |
7694 次 |
| 最近记录: |