为什么SQL语句在“有限”时需要这么长时间?

时间:2009-04-27 02:09:08

标签: sql postgresql

考虑以下pgSQL语句:

SELECT DISTINCT some_field 
  FROM some_table 
  WHERE some_field LIKE 'text%' 
  LIMIT 10;

另外考虑一下,some_table包含数百万条记录,some_field有一个b树索引。

为什么查询执行这么长时间(几分钟)?我的意思是,为什么它不通过创建结果集循环,一旦它得到10个,返回结果?无论您是否包含“限制10”,看起来执行时间都是相同的。

这是正确的还是我错过了什么?有什么我可以做的,让它返回前10个结果并“拧”其余部分?

更新:如果你删除了distinct,结果几乎立即返回。但我确实知道,许多some_table记录已经相当独特,而且当我在没有明确声明的情况下运行查询时,前10个结果实际上是唯一的。我也删除了where子句(将其作为一个因素消除)。所以,我原来的问题仍然存在,为什么一旦找到10个匹配就不会终止?

5 个答案:

答案 0 :(得分:8)

你有一个DISTINCT。这意味着要查找10个不同的行,必须扫描与谓词匹配的所有行,直到找到10个不同的 some_fields。

根据您的索引,查询优化器可能会决定扫描所有行是执行此操作的最佳方式。

10个不同的行可以代表10个,一百万个,无穷大的不同行。

答案 1 :(得分:3)

您可以在查询中发布运行EXPLAIN的结果吗?这将揭示Postgres执行查询的过程,通常是诊断查询性能问题的第一步。

在将第一行返回到LIMIT运算符之前,可能是排序或构造整个行集的哈希表以消除非不同的记录。有意义的是,引擎应该能够读取一小部分记录,一次返回一个新的记录,直到LIMIT子句满足其10个配额,但可能没有实现操作符来使其工作。

some_field是否与众不同?如果不是,那么在查找不同的记录时就没用了。如果是,则DISTINCT子句是不必要的,因为该索引已经保证每个行在some_field上是唯一的。

答案 2 :(得分:2)

任何时候有一个涉及聚合的操作,并且“DISTINCT”肯定有资格,优化器会在考虑下一步之前进行聚合。而aggration意味着扫描整个表(在你的情况下涉及排序,除非有索引)。

但最有可能的交易破坏者是您正在对列上的操作进行分组,而不是普通列值。一旦您对某种列转换进行操作,优化器通常会忽略许多可能的操作。很可能不够聪明,不知道“LIKE'文本%'”和“='text'”的顺序对于分组目的是相同的。

请记住,您正在对列上的操作进行聚合。

答案 3 :(得分:0)

桌子有多大?你桌上有什么索引吗?检查您的查询执行计划,以确定它是在进行表扫描,索引扫描还是索引搜索。如果它正在进行表扫描,那么你很可能没有任何索引。

尝试在您按过滤的字段和/或您选择的字段上添加索引。

答案 4 :(得分:-1)

我很怀疑是因为你没有ORDER BY。如果没有订购,您可能需要巡航大量记录以获得满足您标准的10条记录。