考虑以下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个匹配就不会终止?
答案 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条记录。