我有一个简单的测试表GTable(id int, groupby int, orderby int, padding varchar(1000))
。我在SQL Server 2016,PostgreSQL 9.6.1和Oracle 12c中有这个表,几乎有相同的数据。 Bellow,你可以看到用于在PostgreSQL中创建表的脚本。
PostgreSQL数据
CREATE TABLE GTable (
id INT NOT NULL,
groupby INT NOT NULL,
orderby INT NOT NULL,
padding VARCHAR(1000) NOT NULL
);
INSERT
INTO GTable
SELECT s,
s % 100,
s % 10000,
RPAD('Value ' || s || ' ' , 500, '*')
FROM generate_series(1, 100000) s;
我创建了索引
CREATE INDEX ix_gtable_groupby_orderby ON gtable(groupby, orderby);
并运行以下查询
SELECT groupby, max(orderby) gmax
FROM gtable
GROUP BY groupby;
虽然Oracle和SQL Server使用索引来处理查询(使用顺序扫描),但PostgreSQL却没有。决不。我试图改变选择性,但没有成功。这是PostgreSQL解释(分析,缓冲)
"HashAggregate (cost=8643.00..8643.10 rows=10 width=8) (actual time=54.906..54.907 rows=10 loops=1)"
" Group Key: groupby"
" Buffers: shared hit=4410 read=2733"
" -> Seq Scan on gtable (cost=0.00..8143.00 rows=100000 width=8) (actual time=0.077..32.065 rows=100000 loops=1)"
" Buffers: shared hit=4410 read=2733"
"Planning time: 0.096 ms"
"Execution time: 54.955 ms"
问题
因此,为什么PostgreSQL没有使用索引进行查询?是否有可能在不同的数据分布下使用索引?
的Oracle
如果有人想尝试,我会添加Oracle创建脚本
CREATE TABLE gtable (id NOT NULL, groupby NOT NULL, orderby NOT NULL, padding NOT NULL)
AS
SELECT level,
mod(level, 100),
mod(level * 7 , 10000),
CAST(RPAD('Value ' || level || ' ', 500, '*') AS VARCHAR2(500))
FROM dual
CONNECT BY
level <= 1000000;
修改
我强迫PostgreSQL避免堆扫描,因为@a_horse_with_no_name建议(谢谢),我得到以下查询计划
"HashAggregate (cost=17415.29..17415.39 rows=10 width=8) (actual time=59.014..59.016 rows=10 loops=1)"
" Group Key: groupby"
" Buffers: shared hit=14561"
" -> Bitmap Heap Scan on gtable (cost=1629.29..16915.29 rows=100000 width=8) (actual time=10.396..36.956 rows=100000 loops=1)"
" Heap Blocks: exact=14286"
" Buffers: shared hit=14561"
" -> Bitmap Index Scan on ix_gtable_orderby_groupby (cost=0.00..1604.29 rows=100000 width=0) (actual time=7.975..7.975 rows=100000 loops=1)"
" Buffers: shared hit=275"
"Planning time: 0.127 ms"
"Execution time: 59.260 ms"
他现在使用索引,但无论如何都会访问gtable
。我不明白为什么他仍然访问gtable
,即使结果所需的所有数据都在索引中。 PostgreSQL是否有问题使用具有多个属性的索引?