专注,勤学,慎思。戒骄戒躁,谦虚谨慎

just do it

导航

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;

image

 

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

image

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

 

posted on 2026-07-02 16:40  MSSQL123  阅读(14)  评论(0)    收藏  举报