在我的MySQL数据库中,表事件有一个复合索引,其中包含列lidingeventid,timeStart和eventCode。表事件中有超过2100万行。
这是两个SQL,如果我在MySQL命令行中运行第一个,进程mysqld-nt.exe的Mem Usage逐渐增加,每秒10 M,它上升到1.6 G左右然后直线下降到30 M左右。然后命令行返回Out of Memory异常。
但是,如果我使用第二个SQL,使用INNER JOIN而不是IN,则可以。似乎IN子句没有达到任何索引。
为什么呢?有没有想过监控MySQL执行过程,比如MS SQL的执行计划?
SELECT COUNT(*) AS 'cnt'
FROM events
WHERE
(timeStart < '2010-09-22 14:29:10’)
AND (closingeventid IS NULL)
AND (eventcode IN (SELECT DISTINCT evtcclosed FROM eventclose))`
的 VS 的
SELECT COUNT(1) AS 'cnt'
FROM events
inner join
(SELECT DISTINCT evtcclosed FROM eventclose) ec
ON ec.evtcclosed = events.eventcode
WHERE (timeStart < '2010-09-22 14:29:10’) AND (closingeventid IS NULL)
答案 0 :(得分:4)
MySQL优化器非常糟糕地优化IN (subquery)
子句。它为外部查询的每一行执行嵌套查询。
要获得执行计划 - 只需在查询之前添加EXPLAIN
关键字
EXPLAIN SELECT ...
答案 1 :(得分:0)
谢谢zerkms!
我在两个SQL上尝试了EXPLAIN,但似乎它们都遇到了正确的索引idxEventClosed(closingeventid,timeStart,eventCode)。解释看起来与下面的粗线相同。关于导致内存不足问题的原因,我仍然不太了解。
mysql> EXPLAIN SELECT COUNT(*) AS 'cnt' FROM events WHERE (timeStart < '2010-10-29 14:29:10') AND (closingeventid IS NULL) AND (eventcode IN (SELECT D
ISTINCT evtcclosed FROM eventclose));
+----+--------------------+------------+-------+-------------------------+----------------+---------+------+---------+------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+------------+-------+-------------------------+----------------+---------+------+---------+------------------------------+
| 1 | PRIMARY | events | range | idxStart,idxClosedEvent | idxClosedEvent | 17 | NULL | 4335955 | Using where; Using index |
| 2 | DEPENDENT SUBQUERY | eventclose | ALL | NULL | NULL | NULL | NULL | 10 | Using where; Using temporary |
+----+--------------------+------------+-------+-------------------------+----------------+---------+------+---------+------------------------------+
2 rows in set (0.00 sec)
mysql> EXPLAIN SELECT COUNT(1) AS 'cnt' FROM events inner join (SELECT DISTINCT evtcclosed FROM eventclose) ec on ec.evtcclosed = events.eventcode whe
re (events.closingeventid is null) and (timeStart < '2010-10-28 14:29:10');
+----+-------------+------------+-------+---------------------------------+----------------+---------+------+---------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------------------------+----------------+---------+------+---------+--------------------------+
| 1 | PRIMARY | events | range | evtNLoc,idxStart,idxClosedEvent | idxClosedEvent | 17 | NULL | 4330270 | Using where; Using index |
**| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 8 | Using where |**
| 2 | DERIVED | eventclose | ALL | NULL | NULL | NULL | NULL | 10 | Using temporary |
+----+-------------+------------+-------+---------------------------------+----------------+---------+------+---------+--------------------------+
3 rows in set (0.00 sec)