为什么 PostgreSQL 对索引列执行顺序扫描?

Why does PostgreSQL perform sequential scan on indexed column?

提问人:Alex Vayda 提问时间:3/5/2011 最后编辑:Jørgen RAlex Vayda 更新时间:1/30/2022 访问量:117724

问:

非常简单的示例 - 一个表,一个索引,一个查询:

CREATE TABLE book
(
  id bigserial NOT NULL,
  "year" integer,
  -- other columns...
);

CREATE INDEX book_year_idx ON book (year)

EXPLAIN
 SELECT *
   FROM book b
  WHERE b.year > 2009

给我:

Seq Scan on book b  (cost=0.00..25663.80 rows=105425 width=622)
  Filter: (year > 2009)

为什么它不执行索引扫描? 我错过了什么?

PostgreSQL 索引 序列 数据库扫描

评论


答:

19赞 Frank Heikens 3/5/2011 #1

您是否分析了表/数据库?那么统计数据呢?如果有许多记录显示年份> 2009,则顺序扫描可能比索引扫描更快。

377赞 user330315 3/5/2011 #2

如果 SELECT 返回的行数大约占表中所有行的 5-10%,则顺序扫描比索引扫描快得多。

这是因为索引扫描需要对每一行执行多个 IO 操作(在索引中查找该行,然后从堆中检索该行)。而顺序扫描只需要每行一个 IO - 甚至更少,因为磁盘上的块(页)包含多个行,因此可以使用单个 IO 操作获取多个行。

顺便说一句:对于其他 DBMS 也是如此 - 一些优化,如“仅索引扫描”被搁置一旁(但对于 SELECT *,这样的 DBMS 极不可能进行“仅索引扫描”)

评论

0赞 Alex Vayda 3/5/2011
有趣的是,这为我解释了很多事情:)事实上,当我选择2010年>年份时,它会进行索引扫描。谢谢!
6赞 araqnid 3/6/2011
此外,顺序扫描可以一次从堆中请求多个页面,并要求内核在处理当前块时获取下一个块 - 索引扫描一次获取一个页面。(位图扫描在两者之间做了一个折衷,你通常会看到它出现在一个计划中,这些查询对索引扫描的选择性不够,但仍然不是那么没有选择性,以至于值得进行全表扫描)
14赞 Laurent Grégoire 10/10/2016
有趣的问题是,数据库如何知道查询将返回多少行,而无需先执行查询?它是否在某处存储统计信息,例如不同值的数量与表大小?
11赞 10/10/2016
@LaurentGrégoire:是的,数据库存储有关行数和值分布的统计信息。有关详细信息,请参阅手册:postgresql.org/docs/current/static/planner-stats.html
0赞 brauliobo 3/10/2017
如果您确定索引扫描更好,该怎么办?在本地数据库中,它使用索引并且速度要快得多,在生产环境中,它更喜欢 seq。 扫描
5赞 Gaurav Neema 5/1/2019 #3

在索引扫描中,读取头从一行跳到另一行,这比读取下一个物理块(在顺序扫描中)慢 1000 倍。

因此,如果(要检索的记录数 * 1000)小于记录总数,则索引扫描的性能会更好。

6赞 Shitij Goyal 1/31/2020 #4

@a_horse_with_no_name解释得很好。此外,如果您确实想使用索引扫描,通常应该在 where 子句中使用有界范围。例如 - 2019 > 年和 2020 <年。

很多时候,统计信息不会在表上更新,并且由于限制而可能无法更新。在这种情况下,优化器将不知道在 2019 >年应该占用多少行。因此,它选择顺序扫描来代替完全了解。大多数时候,有界分区可以解决问题。