我正在使用一个mysql服务器,其中我设置了慢速查询日志,其中包含以下设置
log-slow-queries=/var/log/mysql/mysql-slow-queries.log
long_query_time=1
log-queries-not-using-indexes
我在mysql事件中每分钟都设置了以下事件。
UPDATE mytable SET playing = 0
WHERE playing != 0
AND ( TIMESTAMPDIFF( MINUTE , lastplayed, NOW( )) >10 )
OR ( lastplayed IS NULL
AND ispresent= 0
);
现在所有这些列playing, lastplayed, and ispresent
都被编入索引,但这仍然出现在慢速查询日志中,其中包含以下详细信息
# Query_time: 0.000585 Lock_time: 0.000159 Rows_sent: 0 Rows_examined: 316
为什么此查询在慢速日志中显示?
答案 0 :(得分:0)
我的猜测是,当你在函数中使用lastplayed
时(在这种情况下为TIMESTAMPDIFF
),不能使用索引。 MySQL不够聪明,无法理解您正在寻找all lastplayed stamps which are older than 10 minutes
。因此它遍及所有行。
相反,你可以使用它:
... AND lastplayed < DATE_SUB(NOW(), INTERVAL 10 MINUTE) ...
然后MySQL只计算DATE_SUB
ONCE,然后可以将lastplayed
与实际整数值进行比较。这样MySQL再次使用索引就足够聪明了。
详细原因:
想象一下,你编写自己的MySQL函数(伪代码):
function weirdFunction(Integer i): {
if (RAND() < 0.5) return i;
else return 0;
}
现在,当您想要运行查询时:
... AND weirdFunction(lastplayed) = 0 ...
MySQL如何知道哪些最后显示的值会给出哪个结果?它不可能。它需要为所有行执行功能才能找到答案。因此,不能使用索引。
答案 1 :(得分:0)
通过两个OR
摆脱UPDATEs
,OR
的每一面都有一个{<1}}:
UPDATE mytable SET playing = 0
WHERE lastplayed < NOW() - INTERVAL 10 MINUTE;
UPDATE mytable SET playing = 0
WHERE lastplayed IS NULL
AND ispresent= 0;
(假设你有优先权。)
那些需要并使用这个“复合”指数:
INDEX(lastplayed, ispresent)
(每列的单个索引效率不高。)