2009-04-27 59 views
1

考虑以下pgSQL的语句:为什么SQL语句在“有限”时间太长?

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

想想也是,那some_table由几百万条记录,并some_field有一个B树索引。

为什么查询需要很长时间才能执行(几分钟)?我的意思是,为什么不通过创建结果集来循环,一旦获得10个结果集,返回结果?无论您是否包含“LIMIT 10”,执行时间看起来都是一样的。

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

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

回答

8

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

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

10个不同的行可能表示10,100万个无限的非不同行。

-1

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

+0

我认为没有ORDER BY会加快速度。如果您有ORDER BY,则数据库需要返回十个“最低”行,这涉及到排序或所有行(或巧妙使用排序列上的索引)。现在只需要返回找到的前十个(不同的)行。 – Thilo 2009-04-27 02:22:02

+0

这不一定是正确的。例如,我相信这是postgres 8.2或8.3中的一项新功能。其他dbms的支持这种优化可能会有所不同。 – 2009-04-27 02:27:57

2

任何时候都有一个涉及聚合的操作,而“DISTINCT”当然有资格,优化器会在考虑接下来会发生什么之前进行聚合。攻击意味着扫描整个表格(在你的情况下涉及排序,除非有索引)。

但最可能的交易断路器是,您正在对列上的操作进行分组,而不是普通的列值。一旦您使用某种列转换进行操作,优化程序通常会忽略大量可能的操作。如果知道“LIKE”文本%'“和”='文本'“的排序对于分组目的是相同的,那么很可能不够聪明。

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

0

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

尝试在您的过滤字段和/或您选择的字段上放置索引。

3

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

在将第一行返回给LIMIT运算符之前,它可能正在整理或构造整个行集的散列表以消除非独特记录。有意义的是,引擎应该能够读取一小部分记录,一次返回一个新的独特信息,直到LIMIT子句满足其10个配额,但可能没有实现该运行的运营商。

some_field是独一无二的吗?如果不是的话,定位不同的记录是没有用的。如果是这样,那么DISTINCT子句将是不必要的,因为该索引已经确保每行在some_field上是唯一的。