Пустой UPDATE намного медленнее, чем соответствующий SELECT

Я использую MySQL 5.1.73 с InnoDB.

У меня есть очень медленный запрос UPDATE (около 10 с), где количество измененных строк (часто) равно нулю (это занимает примерно столько же времени, если изменено несколько строк):

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 строк, хотя она содержит несколько больших двоичных объектов, поэтому общий размер БД составляет около 800 МБ).

Вопросы:

  • Почему обновление такое медленное?
  • Как я могу отладить это?
  • Как я могу ускорить его?

ОБНОВЛЕНИЕ: я попробовал ту же базу данных на другом сервере с MySQL 5.5.35 (Debian wheezy по умолчанию). Запрос по-прежнему быстрый, а обновление по-прежнему медленное, и до сих пор нет объяснений обновлений... Я могу попробовать перейти на mysql 5.6 с dotdeb или попробовать 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 |
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+-------------+

Это только подтверждает то, что можно было подозревать с самого начала: ОБНОВЛЕНИЕ не использует никаких индексов. Итак, остается вопрос: ПОЧЕМУ?

Я попытаюсь создать минимальный пример, который обеспечивает такое поведение; может быть, в ходе этого я найду некоторые ответы....


person P.Péter    schedule 23.04.2014    source источник
comment
Начните использовать удобную функцию explain mysql. Проверьте документацию для этого.   -  person arkascha    schedule 23.04.2014
comment
Объяснение для обновления доступно только после MySQL 5.6.   -  person P.Péter    schedule 23.04.2014
comment
Какой движок базы данных использует эта таблица? Что говорит SHOW CREATE TABLE job_queue? Если вас беспокоит скорость, MySQL 5.1 ужасно медленный по сравнению с 5.5 или 5.6. MySQL 5.1 был выпущен в 2005 году, и его срок годности давно истек.   -  person tadman    schedule 23.04.2014
comment
Хорошо, извините, мне даже в голову не пришло, что такая старая версия mysql все еще используется :-)   -  person arkascha    schedule 23.04.2014
comment
Я подумаю об обновлении, в настоящее время он работает на виртуальной машине Debian, поэтому, скорее всего, для обновления mysql рекомендуется полное обновление ОС.   -  person P.Péter    schedule 23.04.2014
comment
Используя InnoDB, как можно прочитать в первой строке.   -  person P.Péter    schedule 23.04.2014


Ответы (1)


Я нашел проблему! Столбец state был определен как char(1). Интересно, что SELECT, содержащие state=1, в большинстве случаев используют индексы, а UPDATE — никогда. Однако при указании state="1" всегда используются индексы.

Таким образом, если col является char, а col индексируется:

UPDATE table SET col=2 WHERE col=1

не будет использовать индекс и поэтому будет медленным, тогда как

UPDATE table SET col=2 WHERE col="1"

будет использовать индекс и, следовательно, будет быстрым.

person P.Péter    schedule 24.04.2014