我有一个 SQL 查询(见下文),它准确地返回我需要的内容,但是当运行 phpMyAdmin 时,它需要从 0.0009 秒到 0.1149 秒,有时甚至高达 7.4983 秒。
询问:
SELECT
e.id,
e.title,
e.special_flag,
CASE WHEN a.date >= '2013-03-29' THEN a.date ELSE '9999-99-99' END as date
CASE WHEN a.date >= '2013-03-29' THEN a.time ELSE '99-99-99' END as time,
cat.lastname,
FROM e_table as e
LEFT JOIN a_table as a ON (a.e_id=e.id)
LEFT JOIN c_table as c ON (e.c_id=c.id)
LEFT JOIN cat_table as cat ON (cat.id=e.cat_id)
LEFT JOIN m_table as m ON (cat.name=m.name AND cat.lastname=m.lastname)
JOIN (
SELECT DISTINCT innere.id
FROM e_table as innere
LEFT JOIN a_table as innera ON (innera.e_id=innere.id AND
innera.date >= '2013-03-29')
LEFT JOIN c_table as innerc ON (innere.c_id=innerc.id)
WHERE (
(
innera.date >= '2013-03-29' AND
innera.flag_two=1
) OR
innere.special_flag=1
) AND
innere.flag_three=1 AND
innere.flag_four=1
ORDER BY COALESCE(innera.date, '9999-99-99') ASC,
innera.time ASC,
innere.id DESC LIMIT 0, 10
) AS elist ON (e.id=elist.id)
WHERE (a.flag_two=1 OR e.special_flag) AND e.flag_three=1 AND e.flag_four=1
ORDER BY a.date ASC, a.time ASC, e.id DESC
Run Code Online (Sandbox Code Playgroud)
解释计划:

问题是:这个查询的哪一部分可能导致性能的广泛差异?
要专门回答您的问题:它不是导致广泛性能的查询的特定部分。这就是 MySQL 做它应该做的事情——成为一个关系数据库管理系统 (RDBMS),而不仅仅是一个围绕逗号分隔文件的愚蠢的 SQL 包装器。
执行查询时,会发生以下情况:
您所看到的是,当查询花费 0.0009 秒时,缓存足够新鲜以将所有数据一起提供,当它在 7.5 秒达到峰值时,要么查询表中的某些内容发生了更改,要么其他查询“推送”了内存缓存数据,或者 DBMS 有其他原因怀疑它需要重新编译查询或再次获取所有数据。可能其他一些变化与使用的索引是否仍然在内存中足够新鲜地缓存有关。
总结一下,查询速度慢得离谱,有时您很幸运,缓存使它看起来很快。
为了解决这个问题,我建议研究两件事:
CASE和这样的编程元素COALESCE通常很有用,但它们确实迫使数据库在运行时评估更多的东西,而不仅仅是获取原始表数据。尝试消除此类语句,或将它们移到业务逻辑中作为对检索数据的后处理。最后,永远不要忘记 MySQL 实际上是一个相当愚蠢的 DBMS。它针对大多数网站所需的简单数据获取查询的性能进行了优化。因此,对于大多数通用问题,它比 SQL Server 和 Oracle 快得多。一旦你开始用函数、案例、巨大的连接或匹配条件等使事情复杂化,竞争对手通常会得到更好的优化,并且在他们的查询编译器中有更好的优化。因此,当 MySQL 在特定查询中开始变慢时,请考虑将其拆分为 2 个或更多个较小的查询,以免混淆,并使用 PHP 或您正在调用的任何语言进行一些后处理。我已经看到很多情况,这大大提高了性能,只是不混淆 MySQL,尤其是在涉及子查询的情况下(如您的情况)。