【问题标题】:Why does the following query copy table data?为什么以下查询会复制表数据?
【发布时间】:2010-12-16 15:30:30
【问题描述】:
SELECT COUNT(*) AS cnt
FROM products
WHERE ExternalProductId IS NOT NULL
GROUP BY SourceId, ExternalProductId
HAVING cnt > 1

(ExternalProductId、SourceId、AnotherField)上有一个索引。解释显示使用了索引。这打印在说明的“额外”列中:

Using where; Using index; Using temporary; Using filesort

当我运行查询时,我通过 SHOW PROCESSLIST 看到:

Copying to tmp table on disk

我可以调整这个查询以在索引上工作吗?我也不介意我得到的结果是否由于其他进程同时在此表上工作而稍微不准确 - 我可以更改隔离级别以提高查询的性能吗?

【问题讨论】:

  • 我认为你有一些误解。临时表并不意味着它从表中复制所有数据来完成它的工作。这仅意味着它将一些中间结果复制到临时表中以进行进一步处理。临时表可能包含 ExternalProductID 不为空的所有记录和 cnt 列,因此它可以评估“HAVING”子句。其次,事务隔离与临时表无关。
  • @bot403 - 我刚刚和我们的 DBA 谈过,他同意你的看法。我相信您的评论实际上是迄今为止对这个问题的最佳答案。
  • 是的,我认为答案是我的 #1 和 ajreal 的索引建议。
  • @bt403 - 实际上,看看@Riedsio 的回答,我认为他有一些东西。

标签: mysql database performance group-by covering-index


【解决方案1】:

如果您反转 GROUP BY 中的列以与复合索引的前两个字段的顺序相对应,它将更有效地使用您的复合索引。

SELECT COUNT(*) AS cnt
FROM products
WHERE ExternalProductId IS NOT NULL
GROUP BY ExternalProductId, SourceId
HAVING cnt > 1

您的查询执行原语应该变成'Using where; Using index',并摆脱由另一个GROUP BY引起的临时表和文件排序。

您仍然会得到相同的结果,但顺序会略有不同。

【讨论】:

  • 看起来不错,说明现在确实没有显示临时表。我将测量查询运行时间,看看是否有差异。
【解决方案2】:

有几件事可以尝试:

  1. MySQL 将自动按组排序。如果您不关心排序顺序,请添加“ORDER BY NULL”子句。这将取出文件排序和可能的临时表。

  2. 删除 count(*) 并使用索引中的列名而不是通配符。

还有。你的指数是多少?你能告诉我们完整的表创建语句吗?

【讨论】:

  • ORDER BY NULL 仍然使用临时表 - 请参阅接受的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-18
  • 1970-01-01
  • 1970-01-01
  • 2014-02-01
  • 2020-09-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多