【问题标题】:Why are UNION queries so slow in MySQL?为什么 MySQL 中的 UNION 查询这么慢?
【发布时间】:2010-10-26 14:03:36
【问题描述】:

当我优化我的 2 个单个查询以在 0.02 秒内运行,然后 UNION 它们运行结果查询需要超过 1 秒。此外,UNION ALLUNION DISTINCT 需要更长的时间。

我假设允许重复会使查询运行得更快而不是更慢。 我真的最好分开运行这两个查询吗? 我更喜欢使用UNION

作为一个简单的例子,如果我这样做了

SELECT name FROM t1 WHERE field1 = true

需要 0.001 秒

如果我这样做了

SELECT name FROM t1 WHERE field1 = false

需要 0.1 秒。

如果我然后运行

SELECT name FROM t1 WHERE field1 = true 
UNION ALL 
SELECT name FROM t1 WHERE field1 = false

需要 1 秒以上。

【问题讨论】:

  • 不幸的是我不能(工作),虽然我认为这是一个非常直接的查询。也许我需要一些关于 MySQL 如何执行 UNION 的见解。我注意到对连接查询的解释我使用的是文件排序和临时表,而每个单独的查询都不是。
  • 不是整个脚本,只是相关查询。
  • 举个简单的例子,如果我执行 SELECT name FROM t1 WHERE field1 = true 则需要 0.001,如果我执行 SELECT name FROM t1 WHERE field1 = false 则需要 0.1 秒。如果我然后运行 ​​SELECT name FROM t1 WHERE field1 = true UNION ALL SELECT name FROM t1 WHERE field1 = false 它需要超过 1 秒。它不是特定查询的结果。
  • 我不知道为什么这 10 岁。问题有一个赏金。我测试的 MySQL 没有这个问题:sqlfiddle.com/#!9/4668601/2
  • 也许我们中的一些人希望立即查询每个 SELECT,然后直接合并排序到客户端。

标签: mysql query-optimization union


【解决方案1】:

猜测: 由于您使用 2 个联合查询一个表,因此 mysql 可能难以确定该表的锁定策略,或者它尝试一些缓存,这在此处不起作用,因为您查询不相交的集合,尝试多线程访问(非常合理)但遇到一些锁定/并发/文件搜索问题..

联合通常也可能采用更高的安全设置,因为这两个选择必须是一致的。如果您将它们放入单独的事务中,它们不会。

实验: 复制表格并将其合并。如果我是对的,应该会更快。

可能的解决方案: 将单个文件拆分为多个文件,以实现更好的并发策略。这不会/不应该有助于解决锁定问题,但可以排除数据库中的多线程/搜索问题。

了解您使用的存储引擎会很有用。

好吧,只是我的 2 美分。目前无法在此处进行测试。

【讨论】:

  • 我正在使用 Innodb 和 MyIsam
【解决方案2】:

当我优化我的 2 个单个查询以在 0.02 秒内运行,然后将它们联合起来,生成的查询需要超过 1 秒才能运行。

您的查询是否包含ORDER BY … LIMIT 子句?

如果您在UNION 之后放置ORDER BY … LIMIT,它将应用于整个UNION,并且在这种情况下不能使用索引。

如果id 是主键,则此查询将是即时的:

SELECT  *
FROM    table
ORDER BY id
LIMIT 1

,但这个不会:

SELECT  *
FROM    table
UNION ALL
SELECT  *
FROM    table
ORDER BY id
LIMIT 1

另外,UNION ALLUNION DISTINCT 花费的时间更长。我假设允许重复会使查询运行得更快而不是更慢。

这似乎也是由于ORDER BY。对较小的集合进行排序比对较大的集合进行排序更快。

单独运行这两个查询真的更好吗?我更喜欢使用UNION

您需要对结果集进行排序吗?

如果没有,就去掉最后的ORDER BY

【讨论】:

  • 如果我需要 order by 删除它怎么办。使我的查询耗时 2.5 秒,最长可达 45 秒。
  • @sharif:你希望得到什么样的答案?
  • 不,您必须添加括号才能将ORDER BYLIMIT 应用于UNION(SELECT ...) UNION (SELECT ...) ORDER BY .. LIMIT..
【解决方案3】:

您是否衡量的是响应时间而不是检索所有数据的时间?

【讨论】:

    【解决方案4】:

    关于UNION

    • UNION DISTINCTUNION 的默认值)必然较慢,因为它必须收集两个结果,然后进行 dedup。但是,由于返还给客户的数量较少,因此可能会有一些补偿。
    • 直到最近的版本,所有UNIONs 涉及一个临时表来收集结果,因此UNION 必然比两个单独的SELECTs 慢。 最近,(MySQL 5.7,MariaDB 10.1)UNION ALL 的一些案例进行了改进,将数据从一个SELECT 直接传递到客户端,然后再传递其他的。
    • SELECT .. UNION SELECT .. ORDER BY .. 等价于
      (SELECT .. UNION SELECT ..) ORDER BY .. -- 这个
      (SELECT ..) UNION (SELECT .. ORDER BY ..) -- 不是这个
      建议始终在每个 SELECT 周围使用括号。
    • 排序(通过ORDER BY可能需要额外的时间来处理它所附加的任何内容(选择或联合)。花费更少时间的可能性非常不太可能。简单地说,优化器的目标是做任何最快的事情,这可能碰巧排序。
    • 所有这些语句都适用于 InnoDB; MyISAM 不太受支持,可能缺少一些最近的优化。
    • 有时可以通过将单个 SELECTOR 转换为 UNION 来加速,从而使用两个索引。

    关于测试:

    • 0.001 的时间听起来就像您之前运行过查询,结果缓存在“查询缓存”中。通过关闭 QC 或添加 SQL_NO_CACHE 来避免这种情况。
    • 选择WHERE flag = true (or false) 有几种情况:flag 是否已编入索引? flag 几乎总是这些价值观之一吗?在那种情况下,将使用索引,并且可能比另一种情况更快。
    • 如果您不同意我的任何陈述,请提供一个相反的工作示例。

    【讨论】:

    • 您关于 UNION .. ORDER BY 的陈述似乎不正确。请参阅:docs要将 ORDER BY 或 LIMIT 应用于单个 SELECT,请将子句放在括 SELECT 的括号内”和this fiddle。所以第一个查询等价于第三个。但也许我只是读错了你的答案:-)
    • @PaulSpiegel - 谢谢;固定。
    【解决方案5】:

    UNION ALL 比 UNION 快,因为普通的 UNION 期望在两个连接的数据集中存在需要删除的重复项。如果您可以(通过内部 WHERE 子句)确保没有重复项,则最好使用 UNION ALL 并让数据库引擎优化内部选择。

    对分组结果的结果使用 WHERE 子句成本太高,因为您操作的内部结果超出了您的需要。此外,无法处理数据库引擎的优化——结果没有任何共同点。

    查看此链接了解详情https://dzone.com/articles/performance-tip-for-tuning-sql-with-union

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-07
      • 2012-06-13
      • 1970-01-01
      • 2011-03-11
      • 2013-07-09
      • 2017-10-12
      • 1970-01-01
      • 2017-01-21
      相关资源
      最近更新 更多