【问题标题】:Does SELECT DISTINCT imply Seq Scan?SELECT DISTINCT 是否意味着 Seq Scan?
【发布时间】:2019-03-10 11:01:29
【问题描述】:

我想知道执行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)
  1. 为什么在创建索引后第一次查询时执行 Seq Scan?
  2. 为什么在这种情况下索引扫描比 seq 扫描更昂贵,为什么查询规划器会选择它?

【问题讨论】:

  • @dwir182 我看不出这个链接与这个问题有什么关系。您愿意详细说明吗?
  • 很抱歉链接错误.. 我不能很好地告诉这个但如果你问index scanseq scancost index so expensive希望这个链接能帮助你Perform Seq Scan Not Index Scan和@ 987654323@
  • 这是针对特定的实际示例,还是您只是在研究它?您的数据集是这样的,对于初学者来说,整个索引可能都在 ram 中。在查询完整数据集时,通常不太可能使用 btree 索引,但显然可以。如果您有一个实际示例来说明您正在尝试做什么,那么规范化很可能是通过单独的表和外键实现的最佳答案。

标签: database postgresql


【解决方案1】:

要获得关于表中所有行的查询结果,必须扫描整个表。

避免顺序表扫描的唯一方法是在t1 上创建一个索引并拥有一个最近清理过的表,以便大多数块“全部可见”。然后可以使用“仅索引扫描”,这通常更便宜。

为什么不立即使用仅索引扫描?我不能绝对肯定地回答这个问题,但一个很好的猜测是,当您第一次运行查询时,autovacuum 仍然在桌子上忙碌。

【讨论】:

    猜你喜欢
    • 2014-08-15
    • 1970-01-01
    • 1970-01-01
    • 2015-03-12
    • 2016-05-16
    • 2020-07-29
    • 1970-01-01
    • 2018-07-25
    • 1970-01-01
    相关资源
    最近更新 更多