使用索引优化慢速SQL查询

时间:2011-11-10 15:44:32

标签: mysql indexing

我在优化非常慢的SQL查询时遇到问题。我认为是一个索引问题,但我找不到我必须应用的索引。

这是查询:

SELECT
    cl.ID, cl.title, cl.text, cl.price, cl.URL, cl.ID AS ad_id, cl.cat_id,
    pix.file_name, area.area_name, qn.quarter_name
FROM classifieds cl
/*FORCE INDEX (date_created) */

INNER JOIN classifieds_pix pix ON cl.ID = pix.classified_id AND pix.picture_no = 0
INNER JOIN zip_codes zip ON cl.zip_id = zip.zip_id AND zip.area_id = 132
INNER JOIN area_names area ON zip.area_id = area.id
LEFT JOIN quarter_names qn ON zip.quarter_id = qn.id
WHERE
    cl.confirmed = 1
    AND cl.country = 'DE'
    AND cl.date_created <= NOW() - INTERVAL 1 DAY
ORDER BY
    cl.date_created
desc LIMIT 7

MySQL需要大约2秒才能获得结果,并开始使用pix.picture_no,但如果我强制索引为“date_created”,则查询速度会快得多,并且只需0.030秒。但问题是“INNER JOIN zip_codes ...”并不总是在查询中,如果不是,强制索引会使查询再次变慢。

我一直在考虑通过PHP条件制定解决方案,但我想知道索引的问题是什么。

3 个答案:

答案 0 :(得分:0)

答案 1 :(得分:0)

我实际上会在你所在的所有元素上有一个复合索引,例如

(国家,已确认,date_created)

让国家优先将优化的索引子集首先保留在一个国家/地区,然后在其中,确认,最后是日期范围本身。不要仅仅查询日期索引。由于您按日期排序,因此索引也应该能够对其进行优化。

答案 2 :(得分:0)

以下是有关如何优化查询的几点建议。

  1. 现在功能 - 您在WHERE子句中使用NOW()函数。相反,我建议使用常量日期/时间戳,以允许缓存和优化值。否则,将为WHERE子句中的每一行计算NOW()的值。在需要动态值时,常量值的替代方法是从应用程序添加值(例如,计算当前时间戳并在执行查询之前将其作为常量注入到应用程序中。 要在实现此更改之前测试此建议,只需使用常量时间戳替换NOW()并检查性能改进。
  2. 索引 - 一般情况下,我建议添加一个索引,其中包含WHERE子句的所有列,在本例中为:confirmed,country,date_created。从最能减少数据量的列开始,然后从那里继续前进。确保将WHERE子句调整为索引的相同顺序,否则不会使用索引。
  3. 我使用EverSQL SQL Query Optimizer来获取这些建议(免责声明:我是EverSQL的联合创始人,并谦虚地提供这些建议)。