201

非常简单的例子——一张表,一张索引,一次查询:

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)

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

4

4 回答 4

303

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

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

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

于 2011-03-05T12:33:13.530 回答
17

您是否分析了表/数据库?那么统计数据呢?当有许多年 > 2009 的记录时,顺序扫描可能比索引扫描快。

于 2011-03-05T12:28:20.250 回答
5

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

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

于 2020-01-31T14:27:41.343 回答
3

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

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

于 2019-05-01T13:28:51.540 回答