【问题标题】:Is EXISTS more efficient than COUNT(*)>0?EXISTS 是否比 COUNT(*)>0 更有效?
【发布时间】:2011-07-12 23:42:44
【问题描述】:

我使用的是 MySQL 5.1,我有一个大致如下形式的查询:

select count(*) from mytable where a = "foo" and b = "bar";

在我的程序中,它唯一检查的是这是零还是非零。如果我将其转换为:

select exists(select * from mytable where a = "foo" and b = "bar");

MySQL 是否足够聪明,可以在遇到第一个搜索时停止搜索?或者是否有其他方式与 MySQL 沟通,我的目的只是找出是否有任何记录与此匹配,而我不需要精确计数?

【问题讨论】:

  • 尝试对这两个查询进行解释,您应该会得到答案。您可以发布解释输出,然后 ppl 将帮助您解码。
  • MySQL 极不可能知道优化COUNT(*)>0
  • ANSI 标准说 EXISTS 更好,因为它不应该遍历或评估超出行的“存在”stackoverflow.com/questions/3271455/…
  • Zimbabao:两个查询的 EXPLAIN 是相同的,只是为后一种情况添加了“未使用表”条目。
  • 谁能告诉我第二个语句可以返回什么?

标签: mysql performance exists


【解决方案1】:

是的,当使用 Exists 函数返回一行时,MySQL(实际上是我所知道的所有数据库系统)将停止处理。

您可以在 MySQL 文档中阅读更多内容: If a subquery returns any rows at all, EXISTS subquery is TRUE.

【讨论】:

  • 我不确定 SQLite 是否可以,以及其他简单的数据库。
  • @tc - 是的。甚至 SQLLite 也可以。甚至访问。我还没有遇到过没有的数据库。
  • 任何证明或参考?
  • @itsazzad - If a subquery returns any rows at all, EXISTS subquery is TRUE。为了验证 MySQL 是否会通过评估所有行来确定行数,只需要使用具有足够大数据集的解释计划来验证即可。
  • @НазарТопольський - 完成。
【解决方案2】:

我已经运行了一个包含 1000 个查询的测试。 SELECT EXISTSSELECT COUNT 快大约 25%。将limit 1 添加到SELECT COUNT 没有任何区别。

【讨论】:

  • limit 1 添加到select count 不会有任何区别,因为select count 返回一行。 :-)
  • 25% 只是这一种情况。它可能快 0%(例如,由于缺少足够的索引而需要扫描整个表),也可能快 99%(最佳索引和充分利用它的值)。
【解决方案3】:

我不知道这对优化有多好,但它在功能上应该与exists 相同。例外是如果没有匹配,它将不返回任何行。

SELECT true from mytable where a = "foo" and b = "bar" LIMIT 1;

【讨论】:

  • 这不是可能返回多行,每行都有一个值true
  • 抱歉,我在编辑中忘记了limit 1。感谢您指出这一点!
  • true1 是同义词。请记住,您得到的不是false (0),而是相反情况下的空结果集。
【解决方案4】:

最可靠的方法可能是LIMIT 1,但这不是重点。

如果你有一个像CREATE INDEX mytable_index_a_b ON mytable (a,b) 这样的索引,MySQL 应该足够聪明,可以从索引中返回计数并且根本不会触及任何行。 LIMIT 1 的好处可能可以忽略不计。

如果您在 (a,b) 上没有索引,那么性能将很糟糕。 LIMIT 1 可能会大大降低它的可怕性,但它仍然会很糟糕。

【讨论】:

  • 好吧,我继承了旧代码库,性能很糟糕。 :-)
  • @Ken:浏览数据库并添加一大堆索引可能是值得的
  • 明显的索引已经存在,其中一些是相当大的表,插入性能也很重要。
  • 但是如果有一百万行有 (a,b),那么 COUNT(*) 必然会扫描索引中的一百万行(那里没有进一步优化)LIMIT 1 确实COUNT 完成后才会生效。 Valyo 的 SELECT 1 将在找到第一个匹配项 (a,b) 后停止,EXISTS() 也将停止。
【解决方案5】:

这也可能是一种方法。

select 1 from mytable where a = "foo" and b = "bar" limit 1;

这不会遍历所有满足 where 条件的记录,而是在第一次 'hit' 后返回 '1'。 缺点是需要检查结果,因为返回的记录可能是空的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-14
    • 2011-12-18
    • 1970-01-01
    • 2010-09-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多