PostgreSQL 18 新特性 skip scan,一个鸡肋的功能
skip scan是什么
Skip Scan PostgreSQL 18版本中一个新特性,原理在复合索引中,当前导列缺失、但前导列基数较小的情况下,通过“多次索引扫描”来替代全表扫描的优化技术。
举例:
假设索引为CREATE INDEX idx_1 ON t3(c2, c3);
对于如下两个查询,都能用到索引
WHERE c2 = 10 AND c3 = 563782;
WHERE c2 = 10;
对于非前导列的查询,如下,是无法使用到索引的。
WHERE c3 = 563782;
感觉这个功能非常鸡肋,被人少部分人炒作成什么“令人兴奋的特性”,感觉有点夸张了。
SQLServer中的skip scan特性
开始之前先看一下所谓的skip scan在SQLServer中的表现,SQLServer中没有强调skip scan是一个特性,印象中是自古以来就有的特性,执行计划中体现为Index Scan。
如下测试环境为SQLServer 2019,对于上文中的场景,SQLServer的index scan在查询条件非索引的前导列的情况下,通过“扫描”索引实现查询的目的,如下case
另:SQLServer真正实现索引查找的叫index seek,也即二分法查询,而index scan是索引扫描,扫整个索引。
create table t1
(
c1 int identity(1,1),
c2 int,
c3 int,
c4 varchar(100),
constraint pk_t1 primary key(c1)
);
create index idx_1 on t1(c2,c3);
while 1>0
begin
insert into t1
select rand()*100000,rand()*1000000,newid()
end
select count(1) from t1;
select * from t1 where c3 = 594981;

PostgreSQL 18 的skip scan
如下测试环境为PostgreSQL 18.3,对于上文中的场景,前导列,这里的基数超过10000的话,就不会走index scan了,而是走全表扫描Seq Scan ,这里有一个限制,既然是这样,那为什么不把基数更大的字段作为前导列呢,Skip Scan又有什么意义呢
create table t3
(
c1 int generated always as identity,
c2 int,
c3 int,
c4 varchar(100),
constraint pk_t1 primary key(c1)
);
truncate table t3;
INSERT INTO public.t3 (c2, c3, c4)
SELECT
random()*100000, --前导列,这里的基数超过100000的话,就不会走skip scan了,而是走全表扫描Seq Scan ,这里有一个限制,既然是这样,那为什么不把基数更大的字段作为前导列呢,Skip Scan又有什么意义呢
random()*1000000,
clock_timestamp()
FROM generate_series(1, 1000000);
select * from t3 limit 100;
create index idx_1 on t3(c2,c3);
analyze t3;
explain analyze
select * from t3 where c3 = 563782

只有在前导列的基数足够小的情况下,类似查询才会使用到 skip scan,正如上面提到的,如果说测试case中的c2的基数足够小,如下case,那么在创建复合索引的时候,把c2放在前面合理吗?
如果把c3作为前导列,也即create index idx_1 on t3(c3,c2);那么,就完全用不到skip scan的特性了。
那么就不需要用到skip scan这个特性了,所以感觉这个特性很鸡肋,同时对比SQLServer,实现的也不怎么好。基数稍微大一点就无法用到skip scan这个特性了。
浙公网安备 33010602011771号