PERFORM * vs PERFORM 1

时间:2013-10-17 09:43:53

标签: sql postgresql query-performance

需要运行查询以查看至少存在一条记录的位置。所以问题是“什么更有效”:

PERFORM * FROM table 

PERFORM 1 FROM table

为什么?

2 个答案:

答案 0 :(得分:2)

应该注意,首先,PERFORM不是SQL指令,它是一个plpgsql关键字,指示解释器运行等效的SELECT,然后丢弃结果。

每个文档(Executing a Command With No Result):

  

PERFORM查询;
  这会执行查询并丢弃结果。写查询相同   你会写一个SQL SELECT命令,但替换初始   关键字SELECT与PERFORM。对于WITH查询,请使用PERFORM然后   将查询放在括号中。 (在这种情况下,查询只能   返回一行。)PL / pgSQL变量将被替换为查询   就像没有返回结果的命令一样,并且计划被高速缓存   一样的方法。此外,特殊变量FOUND如果设置为true   查询产生至少一行,如果没有产生行,则为false

所以问题是这样的:SELECT * FROM tableSELECT 1 FROM table如何进行比较以检查表中是否至少有一行?但问题是,如果表格有很多行,那么它们在性能方面都是不合适的,事实上实际上是荒谬的。

让我们用最新的PostgreSQL 9.3测试一个真实的例子:两个大表:

  • words(int,text)(340万行,文本列总是很小)
  • inverted_word_index(int,int,bytea,int)(约1000万行,字节平均宽度为400字节,最大为2kB)

连续几次重复查询,我只用psql的\timing on

保持最快的执行速度

使用第一个表格测试1

从单词中获得表现1:

mlists=> do $$ begin perform  1 from words; end; $$;
DO
Time: 521,379 ms

PERFORM *来自单词:

mlists=> do $$ begin perform  * from words; end; $$;
DO
Time: 442,800 ms

结果1 :在此表中,perform *似乎始终比perform 1快一点。

使用第二个表格测试2

来自inverted_word_index的PERFORM 1:

mlists=> do $$ begin perform  1 from inverted_word_index ; end; $$;
DO
Time: 2206,230 ms

来自inverted_word_index的PERFORM *:

mlists=> do $$ begin perform  * from inverted_word_index ; end; $$;
DO
Time: 16848,971 ms

结果2 :对于此表,perform *的最佳执行速度比perform 1的最佳执行速度慢得多,因此与之前的结果相反。

结论:一般没有赢家,似乎取决于表格内容。

但真正有趣的一点是,两种方法都是全扫描而不是停在第一行,所以它们都太慢了。

合理快速的方法

mlists=> do $$ begin perform  1 from words limit 1; end; $$;
DO
Time: 0,330 ms

mlists=> do $$ begin perform  * from words limit 1; end; $$;
DO
Time: 0,405 ms

mlists=> do $$ begin perform  1 from inverted_word_index limit 1; end; $$;
DO
Time: 0,333 ms

mlists=> do $$ begin perform  * from inverted_word_index limit 1; end; $$;
DO
Time: 0,314 ms

重复执行表明两种构造的持续时间在0.3毫秒到0.4毫秒之间变化,没有获胜者。速度差异来自不相关的动态因素。

答案 1 :(得分:0)

我不确定你为什么要放弃这个结果。

就个人而言,我会使用以下内容:

select count(*)
into   rows_exist
from   (select * from my_table limit 1) t;

保证返回值为0或1的单行,并且只读取表中的一行才能执行此操作。

至于“1”与“*” - 我的直觉是说优化器足够聪明,只能读取所需的列才能回答查询。

但是,如果您运行explain with (verbose true),则表示所有列都是从子查询中投影的。如果是这种情况,那么使用“select *”可能效率较低,特别是如果从表的开头删除了大量行并且使用“select *”导致许多块被完整读取找到第一个之前的表扫描。我欢迎来自PostgreSQL内部专家的意见,看看这是否是对该计划的正确解释。