为什么SELECT *比按名称选择所有列(以不同的列顺序)要快得多?


12

在具有a,b,c,d,e,f,g,h,i,j,k列的表上,我得到:

select * from misty order by a limit 25;
Time: 302.068 ms

和:

select c,b,j,k,a,d,i,g,f,e,h from misty order by a limit 25;
Time: 1258.451 ms

有没有一种方法可以使按列选择速度如此之快?

更新:

在表上没有索引,新创建了一个

这是EXPLAIN ANALYZE,似乎不太有用:

explain analyze select * from misty order by a limit 25;

Limit  (cost=43994.40..43994.46 rows=25 width=190) (actual time=404.958..404.971 rows=25 loops=1)
->  Sort  (cost=43994.40..45731.11 rows=694686 width=190) (actual time=404.957..404.963 rows=25 loops=1)
     Sort Key: a
     Sort Method: top-N heapsort  Memory: 28kB
     ->  Seq Scan on misty  (cost=0.00..24390.86 rows=694686 width=190) (actual time=0.013..170.945 rows=694686 loops=1)
Total runtime: 405.019 ms
(6 rows)

和:

explain analyze select c,b,j,k,a,d,i,g,f,e,h from misty order by a limit 25;

Limit  (cost=43994.40..43994.46 rows=25 width=190) (actual time=1371.735..1371.745 rows=25 loops=1)
->  Sort  (cost=43994.40..45731.11 rows=694686 width=190) (actual time=1371.733..1371.736 rows=25 loops=1)
     Sort Key: a
     Sort Method: top-N heapsort  Memory: 28kB
     ->  Seq Scan on misty  (cost=0.00..24390.86 rows=694686 width=190) (actual time=0.015..516.355 rows=694686 loops=1)
Total runtime: 1371.797 ms
(6 rows)

列是否已建立索引?你可以发表解释分析吗?
user_0 2015年

1
您需要注意连续进行两次选择并比较时间。第二个查询的缓存中的数据可能会造成时间差异。
Walter Mitty 2015年

1
我也看到了差异,尽管差异不那么明显。我的表的行数= 514431,宽度= 215,对于这种select *情况,我得到大约1.5s,对于select而言,我得到大约2.2s,列以不同的顺序列出。
Colin't Hart

如果我按照表中定义的顺序列出所有列,则获得的时间与I大致相同select *
Colin't Hart 2015年

2
标题具有误导性。问题实际上是为什么排序的持续时间取决于输出列的顺序。
DanielVérité2015年

Answers:


12

这被发布到pgsql-hackers邮件列表中,我试图在那里简短回答。看来,如果目标列表(指定的列)与关系的元组描述符完全匹配,即在列数和顺序上都匹配,则基础扫描可以返回由封闭的Sort节点直接消耗的元组。另一方面,如果目标列表不匹配(顺序或指定列数不匹配),则扫描将返回一种元组形式,这需要Sort的数据准备步骤来执行额外的工作(从内部元组格式转换为由排序代码直接使用的格式)。

顺便说一句,“ *”在内部转换为一个列表,该列表(直观地)与该关系的元组描述符匹配。

编辑:如果您查看后者的EXPLAIN ANALYZE的Seq Scan的实际时间,则可以看到它比前者更多。之所以发生这种情况,是因为扫描执行了额外的投影步骤(即将堆元组转换为内部values [],nulls []格式)。并且由于这种情况发生,上层Sort节点必须在其数据初始化中做额外的工作,即将其转换回实际排序步骤可以理解的元组格式。从Sort的启动成本中可以明显看出这一点。在前一种情况下不会发生这种情况。也就是说,扫描都将按原样返回元组,并且sort的初始化步骤只是将其复制。


@ Colin'tHart,希望这是有道理的。
阿米特兰2015年

是。我希望可以通过使用一些“指针改组”来跳过该步骤或使其更短,但这是针对pgsql黑客的讨论。
Colin't Hart 2015年

随着最近逻辑列排序工作的复苏,可能会有一些改进。
阿米特兰2015年

我已经在考虑并且希望如此!
Colin't Hart 2015年

亲爱的先生,如果我只需要一些列而不是全部,那会更快吗?选择*还是选择some_of_columns?非常感谢。
sgon00
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.