我正在使用带有InnoDB的MySQL 5.1.73
我有一个非常慢的UPDATE查询(大约10s),其中更改的行数(通常)为零(如果更改了几行,则需要大约相同的时间):
UPDATE job_queue SET state=4 WHERE error_counter>=5 AND state=1;
Query OK, 0 rows affected (9.33 sec)
然而,相应的SELECT非常快:
SELECT id FROM job_queue WHERE error_counter>=5 AND state=1;
Empty set (0.03 sec)
EXPLAIN SELECT id FROM job_queue WHERE error_counter>=5 AND state=1;
+----+-------------+-----------+-------+--------------------------------------------+---------------------+---------+------+-------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+--------------------------------------------+---------------------+---------+------+-------+--------------------------+
| 1 | SIMPLE | job_queue | index | Allinone,state_timeout,state_error_counter | state_error_counter | 5 | NULL | 13515 | Using where; Using index |
+----+-------------+-----------+-------+--------------------------------------------+---------------------+---------+------+-------+--------------------------+
正如您所看到的,这是(应该是?)一个索引查询,在一个不太大的数据库上(大约9000行,虽然它确实包含一些blob,因此总DB大小约为800MB)。
问题是:
更新: 我在MySQL 5.5.35(Debian wheezy默认)的不同服务器上尝试了相同的数据库。查询仍然很快,更新仍然很慢,并且仍然没有更新的解释...我可能尝试从dotdeb升级到mysql 5.6,或尝试mariadb。 :)
更新2 : 我尝试了不同的行格式(动态和压缩),但它也没有(显着)更快。
更新3 : 我更新到MySQL 5.6.17(来自dotdeb),性能基本相同,但我终于得到了更新的解释:
EXPLAIN UPDATE job_queue.job_queue SET state=4 WHERE error_counter>=5 AND state=1;
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+-------------+
| 1 | SIMPLE | job_queue | index | NULL | PRIMARY | 8 | NULL | 70222 | Using where |
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+-------------+
这只能确认一直存在的问题:UPDATE没有使用任何索引。所以问题仍然存在:为什么?
我将尝试创建一个产生此行为的最小示例;也许在此过程中,我会找到一些答案......
答案 0 :(得分:1)
我发现了这个问题! state
列定义为char(1)
。有趣的是,大多数时候包含state=1
的SELECT确实使用了索引,但从不使用UPDATE。但是,指定state="1"
始终使用索引。
总而言之,如果col
是char
且col
被编入索引:
UPDATE table SET col=2 WHERE col=1
不会使用索引,因此慢,而
UPDATE table SET col=2 WHERE col="1"
将使用索引,因此快速。