提问人:Alex Vayda 提问时间:3/5/2011 最后编辑:Jørgen RAlex Vayda 更新时间:1/30/2022 访问量:117724
为什么 PostgreSQL 对索引列执行顺序扫描?
Why does PostgreSQL perform sequential scan on indexed column?
问:
非常简单的示例 - 一个表,一个索引,一个查询:
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)
为什么它不执行索引扫描? 我错过了什么?
答:
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 >年应该占用多少行。因此,它选择顺序扫描来代替完全了解。大多数时候,有界分区可以解决问题。
评论