【问题标题】:Any tips to improve MySQL query?任何改进 MySQL 查询的技巧?
【发布时间】:2012-04-15 18:18:38
【问题描述】:

我有一个包含 500K 行的表,如下所示:http://d.pr/njFJ

这样的查询有时通常需要超过 2 秒:

SELECT * 
FROM `alerts` 
WHERE `a_timestamp` > '2012-04-15' AND `a_timestamp` <= '2012-04-16'  
   AND a_company_id IN(64,65,69,70,71,72,73,74,75,76,83,86,106,108,109,116,148) ORDER BY a_id DESC

这里是解释查询:http://d.pr/z20b

有人能指出我做错了什么吗?也许我错过了一些东西。这么小的桌子要花那么多时间吗?

【问题讨论】:

  • @Joel:) 他们在哪里?图像清晰。
  • 您是否尝试反转索引中列的顺序? IE。 a_company_id, a_timestamp?
  • 很奇怪,图像对我来说还可以。编辑以显示外部链接。 @NikolaMarkovinović - 是的,我所看到的并没有改善任何东西。

标签: mysql performance indexing query-optimization


【解决方案1】:

正如 KingFisher 提到的,去掉 IN 子句(这通常是查询性能的瓶颈)并用 JOIN 替换它,但不要使用临时表,这就是你的做法:

SELECT alerts.* FROM (
    (SELECT 64 AS id) UNION (SELECT 65) UNION (SELECT 69) UNION (SELECT 70)
    UNION (SELECT 71) UNION (SELECT 72) UNION (SELECT 73) UNION ...
) AS ids
INNER JOIN alerts ON (ids.id = alerts.a_company_id)
WHERE alerts.a_timestamp > '2012-04-15' AND alerts.a_timestamp <= '2012-04-16'
ORDER BY ids.id DESC

并确保您在a_company_id 上有一个索引。

【讨论】:

  • 谢谢,会试试的。时间戳上的单独索引和 a_company_id 上的单独索引?
  • 对于这个查询,只有a_company_id 上的索引很重要我不认为MySql 在这里使用a_timestamp 上的索引。
【解决方案2】:

尽量去掉IN子句。它扫描整个表中的每个值 IN clause 导致性能下降。

您可以使用临时表来存储 id,并在临时表中使用 JOIN 和 id,而不是使用 in 子句,

【讨论】:

  • 嗯。这是所有 IN 的问题还是仅在我的特定情况下?在这种情况下,我可以删除 company_id 条件并使用 PHP 对其进行过滤——实际上并没有太多。有趣的是,EXPLAIN 查询仅显示 1087 行...
【解决方案3】:

尝试在 (a_company_id, a_timestamp) 上创建索引...与 type_ts_company 索引相反的顺序。

【讨论】:

  • 最终的问题是时间戳上的范围查询无法使用索引,因为范围查询没有很好地优化。反转索引允许 company_id IN 限制范围查询必须查看的值 - 因为它只需要检查公司 ID 列表中的值,而不是表中的所有值。
  • 范围查询绝对可以使用索引。如果范围列不是索引键中的最后一个,则效率不高。如果此数据库中有数千个 company_id,并且索引中的 range 列在前,mysql 将不得不过滤掉数千个不匹配的 company_id。但是,如果 company_id 是第一个,它可以对每个单独的 company_id 进行范围搜索。这样做十几个比过滤掉数千条不匹配的记录要好。
猜你喜欢
  • 2010-10-10
  • 2020-11-18
  • 1970-01-01
  • 1970-01-01
  • 2019-11-28
  • 1970-01-01
  • 1970-01-01
  • 2015-12-12
  • 1970-01-01
相关资源
最近更新 更多