【问题标题】:Improving query performance/rewriting query to be faster on MySQL提高查询性能/重写查询以在 MySQL 上更快
【发布时间】:2012-10-19 02:20:09
【问题描述】:

我有几个查询对我数据库中当前的数据运行非常缓慢(几分钟),我想提高它们的性能。不幸的是,它们有点复杂,所以我通过谷歌获得的信息不足以让我弄清楚要添加哪些索引,或者我是否需要重写我的查询或什么......我希望有人能提供帮助。如果设置正确,我不认为它们应该这么慢。

第一个查询是:

SELECT i.name, i.id, COUNT(c.id) 
FROM cert_certificates c 
JOIN cert_histories h ON h.cert_certificate_id = c.id 
LEFT OUTER JOIN inspectors i ON h.inspector_id = i.id
LEFT OUTER JOIN cert_histories h2 
  ON (h2.cert_certificate_id = c.id AND h.date_changed < h2.date_changed)
WHERE (h.cert_status_ref_id = ? OR h.cert_status_ref_id = ?) 
  AND h2.id IS NULL
GROUP BY i.id, i.name
ORDER BY i.name

第二个查询是:

SELECT l.letter, c.number
FROM cert_certificates c 
JOIN cert_type_letter_refs l ON c.cert_type_letter_ref_id = l.id
JOIN cert_histories h ON h.cert_certificate_id = c.id
LEFT OUTER JOIN cert_histories h2 
  ON (h2.cert_certificate_id = c.id AND h.date_changed < h2.date_changed)
WHERE h.cert_status_ref_id = ? 
  AND h2.id IS NULL 
  AND h.inspector_id = ?
ORDER BY l.letter, c.number

cert_certificates 表与 cert_histories 表一样包含近 19k 条记录(尽管未来该表预计将增长到 cert_certificates 表大小的大约 2-3 倍)。其他的桌子都很小;每条记录少于 10 条。

目前唯一的索引是每个表的 id 和 cert_certificates.number。我在几个地方(例如here)阅读以添加外键索引,但在cert_histories 表的情况下,几乎所有列(cert_certificate_id、inspector_id、cert_status_ref_id)也是not advisable(根据该问题的一些答案,例如 Markus Winand 的),所以我有点迷路了。

任何帮助将不胜感激。

ETA:EXPLAIN 对第一个查询的结果是(对不起,可怕的格式;我使用的是 SQLyog,它在一个不错的表中显示它,但似乎 StackOverflow 不支持表?):

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE h ALL NULL NULL NULL NULL 19740 使用 where;使用临时的;使用文件排序
1 简单我参考 index_inspectors_on_id index_inspectors_on_id 768 marketing_development.h.inspector_id 1
1 SIMPLE c ref index_cert_certificates_on_id index_cert_certificates_on_id 768 marketing_development.h.cert_certificate_id 91 在哪里使用;使用索引
1 SIMPLE h2 ALL NULL NULL NULL NULL 19740 使用where

第二次查询:

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE h ALL NULL NULL NULL NULL 19795 使用 where;使用临时的;使用文件排序
1 SIMPLE c ref index_cert_certificates_on_id index_cert_certificates_on_id 768 marketing_development.h.cert_certificate_id 91 使用 where
1 SIMPLE l ALL index_cert_type_letter_refs_on_id NULL NULL NULL 5 使用 where;使用连接缓冲区
1 SIMPLE h2 ALL NULL NULL NULL NULL 19795 使用where

【问题讨论】:

  • 这没有帮助。我仍然不知道问题出在哪里。
  • 将排除加入更改为NOT EXISTS 有帮助吗?
  • 呃...我的意思是你可以在这里包含EXPLAIN 的结果,不是吗?
  • 使用EXPLAIN your_query 的完整输出编辑您的问题,以便我们为您提供更好的建议。
  • 而且,顺便说一句,我错过了什么吗?为什么需要在JOIN 条件中包含 `AND h.date_changed

标签: mysql sql


【解决方案1】:

您应该在连接字段上创建索引:

cert_certificates.cert_type_letter_ref_id
cert_histories.cert_certificate_id
cert_histories.date_changed
cert_histories.inspector_id

【讨论】:

  • 我刚试过这个。结果是惊人的。即使是最慢的查询也可以在不到一秒的时间内完成。非常感谢。我不知道索引可以使 大不同。
猜你喜欢
  • 2016-12-12
  • 2011-12-03
  • 2023-04-08
  • 2020-07-17
  • 2012-02-07
  • 1970-01-01
  • 1970-01-01
  • 2023-03-14
  • 2016-07-19
相关资源
最近更新 更多