slava=# explain (analyze) SELECT * from pending_posts WHERE user_id <> 1456
slava-# ;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
Seq Scan on pending_posts (cost=0.00..17906.00 rows=999994 width=14) (actual time=0.021..231.803 rows=999994 loops=1)
Filter: (user_id <> 1456)
Rows Removed by Filter: 6
Planning time: 0.108 ms
Execution time: 289.845 ms
(5 rows)
slava=# explain (analyze) select * from pending_posts where user_id <> 1456 order_by user_id;
ERROR: syntax error at or near "order_by"
LINE 1: ...select * from pending_posts where user_id <> 1456 order_by u...
^
slava=# explain (analyze) select * from pending_posts where user_id <> 1456 order by user_id;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------
Index Scan using p_i on pending_posts (cost=0.42..50103.17 rows=999994 width=14) (actual time=0.033..899.520 rows=999994 loops=1)
Filter: (user_id <> 1456)
Rows Removed by Filter: 6
Planning time: 0.141 ms
Execution time: 953.982 ms
(5 rows)
Run Code Online (Sandbox Code Playgroud)
鉴于这user_id是用 btree 索引的整数,排序然后使用树搜索进行选择是否应该更快?
PostgreSQL 将评估所有(或大量)可能的查询计划,并很好地猜测哪个成本最低。如果不同的成本参数(例如,取决于磁盘速度;可用内存量等)设置得很好,大多数情况下猜测将是准确的,并且计划的选择将是最佳的。
你问 PostgreSQL 两个不同的查询。一个不需要排序,另一个需要。返回的行是相同的,因为查询的其余部分是相同的。带有 的查询ORDER BY需要更长的时间。这是可以预料的。
PostgreSQL可以决定执行Seq Scanthen aSort比执行Index Scan. 在实际设置中,它决定了相反的结果。
执行Index Scan时间比执行长Seq Scan只是因为,扫描索引的时候,PostgreSQL的可以直接跳过与项目(user_id <> 1456)(该信息用于user_id 为索引)。对于未跳过的值,它获取对相应行(也是索引的一部分)的(内部)引用,并且必须检索实际的行的表。不需要对它们进行排序,因为按照索引,值已经按正确顺序排列了。
在标准设置下,forseq_page_cost和random_page_cost(以任意单位)的成本是 4 和 1。这考虑到,对于 HDD,从一页跳转到另一页需要大量的机械运动,并且需要比一页一页一页地阅读更多的时间. 您可以假设 aSeq Scan将按顺序读取页面,而 anIndex Scan将主要从一个页面跳转到另一个页面。[如果您使用 SSD 而不是 HDD,则 的值random_page_cost可能应该仅为 1.05]。
如果您将使用覆盖索引(一个索引至少包含您的 中的所有列SELECT),那么 PostgreSQL 将能够执行Index Only Scan(意味着它不必从实际的 *table 中检索整行)。这将显着加快您的查询速度。要使覆盖索引起作用,您的表必须得到妥善维护(即:autovacuum 必须有时间维护它)。
试试这个查询,看看执行计划是什么:
EXPLAIN (analyze)
SELECT user_id
FROM pending_posts
WHERE user_id <> 1456
ORDER BY user_id ;
Run Code Online (Sandbox Code Playgroud)
如果您没有得到Index Only Scan,请执行:
VACUUM ANALYZE pending_posts ;
Run Code Online (Sandbox Code Playgroud)
并重试。
请注意,索引可以在几个方面为您提供帮助:
SELECT子句中,如果它们覆盖索引。如果索引包含所有指定的列,Index Only Scans则是可能的。WHERE子句中是否允许过滤掉(或直接转到)特定的行。ORDER BY子句中,如果他们已经按照您指定的排序顺序提供了行。GROUP BY,如果聚合是通过根据组对行进行排序来完成的(其他技术也是可能的)。参考资料: