database - SELECT DISTINCT 是否意味着 Seq Scan?
问题描述
我想知道执行SELECT DISTINCT
查询是否意味着顺序扫描,以及如何优化它。
我创建了一个虚拟表并确认当没有索引时,SELECT DISTINCT
执行 Seq Scan。
test=# create table test2 (id SERIAL, t1 text);
CREATE TABLE
test=# insert into test2 select generate_series(0, 100000) AS id, md5(random()::text) AS t1;
INSERT 0 100001
test=# explain analyze select distinct t1 from test2;
结果是:
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=2157.97..2159.97 rows=200 width=32) (actual time=54.086..77.352 rows=100000 loops=1)
Group Key: t1
-> Seq Scan on test2 (cost=0.00..1893.18 rows=105918 width=32) (actual time=0.012..12.232 rows=100001 loops=1)
Planning time: 0.079 ms
Execution time: 86.345 ms
(5 rows)
当我们创建索引时:
test=# create index test2_idx_t1 on test2 (t1);
CREATE INDEX
test=# explain analyze select distinct t1 from test2;
结果是:
第一次:
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=2084.01..2086.01 rows=200 width=32) (actual time=48.871..74.617 rows=100000 loops=1)
Group Key: t1
-> Seq Scan on test2 (cost=0.00..1834.01 rows=100001 width=32) (actual time=0.009..9.891 rows=100001 loops=1)
Planning time: 0.145 ms
Execution time: 83.564 ms
(5 rows)
第二次及以后:
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------
Unique (cost=0.42..7982.42 rows=100001 width=33) (actual time=0.016..80.949 rows=100000 loops=1)
-> Index Only Scan using test2_idx_t1 on test2 (cost=0.42..7732.42 rows=100001 width=33) (actual time=0.015..53.396 rows=100001 loops=1)
Heap Fetches: 100001
Planning time: 0.053 ms
Execution time: 87.552 ms
(5 rows)
- 为什么在创建索引后第一次查询时会执行 Seq Scan?
- 为什么在这种情况下索引扫描比 seq 扫描更昂贵,为什么查询规划器会选择它?
解决方案
要获得关于表中所有行的查询结果,必须扫描整个表。
避免顺序表扫描的唯一方法是建立一个索引t1
并拥有一个最近清理过的表,以便大多数块“全部可见”。然后可以使用“仅索引扫描”,这通常更便宜。
为什么不立即使用仅索引扫描?我不能绝对肯定地回答这个问题,但一个很好的猜测是,当您第一次运行查询时,autovacuum 仍然在桌子上忙碌。
推荐阅读
- javascript - 在正确的上下文中执行 Onload 属性 js
- python - 如何使用python从excel中的特定列中提取不可见的评论
- java - Vaadin 组合框返回 null
- java - 在 Leanft 中获取 MessageTypeNotSupportedException
- javascript - 在 React 项目中导入库
- html - 引导 4 卡 - 具有可变标题行行的垂直对齐主体
- c - 查找与一个字符串的结尾和下一个字符串的开头匹配的最长子字符串
- javascript - 无法从节点 js 模块导出变量
- c++ - 程序切换到release后找不到DLL头文件
- java - 集成还是单元测试?在不访问外部系统的情况下测试类