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

为什么PostgreSQL对索引列执行顺序扫描?,postgresql,indexing,sequence,database-scan,Postgresql,Indexing,Sequence,Database Scan,非常简单的示例-一个表、一个索引、一个查询: 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..

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

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)
为什么它不执行索引扫描呢?
我遗漏了什么?

您是否查看了表/数据库?那这个呢?当有许多记录的年份>2009时,顺序扫描可能比索引扫描快。

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

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


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

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


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

@a_horse_with_no_name对其进行了很好的解释。另外,如果您真的想使用索引扫描,通常应该在where子句中使用有界范围。例如 年份>2019年,年份<2020年


很多时候,表上的统计信息并没有更新,而且由于受到限制,可能无法更新。在这种情况下,优化器将不知道在2019年以后需要多少行。因此,它选择顺序扫描来代替完整的知识。有界分区在大多数情况下都能解决问题。

@Frank:这就是我说“大约”的原因:)但谢谢你指出它的有趣之处,这对我解释了很多事情:)事实上,当我选择by year>2010时,它会进行索引扫描。非常感谢。此外,顺序扫描可以一次从堆中请求几个页面,并要求内核在处理当前块时提取下一个块-索引扫描一次提取一个页面。(位图扫描是两者之间的折衷,您通常会看到,在计划中出现的查询对于索引扫描来说没有足够的选择性,但仍然没有选择到值得进行全表扫描)有趣的问题是,数据库如何知道查询将返回多少行而不首先执行?它是否在某处存储诸如不同值的数量与表大小之类的统计信息?@LaurentGrégoire:是的,数据库存储关于行数和值分布的统计信息。有关详细信息,请参阅手册: