Mysql Обновление производительности внезапно ужасно - PullRequest
1 голос
/ 22 апреля 2011

MySQL 5.1, Ubuntu 10.10 64bit, виртуальная машина Linode.

Все таблицы InnoDB .

Одна из наших производственных машин использует базу данных MySQL, содержащую 31 связанную таблицу. В одной таблице есть поле, содержащее отображаемые значения, которые могут изменяться несколько раз в день в зависимости от условий.

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

Один раз за ночь скрипт очищает все отображаемые значения, хранящиеся в таблице, и пересчитывает их все, тем самым фиксируя все возможные изменения. Это гораздо более дорогая операция.

Все это работает последовательно в течение примерно 6 месяцев. Внезапно, 3 дня назад, время выполнения ночного сценария изменилось в среднем с 40 секунд до 11 минут.

Общие пропорции хранимых данных существенно не изменились.

Я исследовал как мог, и часть скрипта, которая неожиданно работает медленнее, является последним оператором обновления, который записывает новые отображаемые значения. Он выполняется один раз для каждой строки с учетом (INT (11)) идентификатора строки и нового отображаемого значения (также INT).

update `table` set `display_value` = ? where `id` = ?

Самое смешное, что очистка всех предыдущих значений выполняется как:

update `table` set `display_value` = null

И это утверждение по-прежнему работает с той же скоростью, что и всегда.

Поле display_value не проиндексировано. id является первичным ключом. В table есть еще 4 внешних ключа, которые не изменяются во время выполнения.

И последний изогнутый шар: если я дам эту схему в тестовую виртуальную машину и выполню тот же сценарий, он будет запущен за 40 секунд, а не за 11 минут. Я не пытался перестроить схему на производственном компьютере, поскольку это просто не долгосрочное решение, и я хочу понять, что здесь происходит.

Что-то не так с моими индексами? Они запутались в них после тысяч обновлений в тех же строках?


Обновление

Мне удалось полностью решить эту проблему, запустив оптимизацию в схеме. Поскольку InnoDB не поддерживает оптимизацию, это вызвало перестройку и решило проблему. Возможно, у меня был поврежденный индекс?

mysqlcheck -A -o -u <user> -p

1 Ответ

2 голосов
/ 22 апреля 2011

Существует вероятность, что оператор UPDATE не будет использовать индекс для id, однако это очень маловероятно (если вообще возможно) для запроса, подобного вашему.

Есть ли вероятность того, что ваша таблица заблокирована длительным параллельным запросом / DML? Какой двигатель использует таблица?

Кроме того, обновление таблицы запись за записью неэффективно. Вы можете массово загрузить свои значения во временную таблицу и обновить основную таблицу одной командой:

CREATE TEMPORARY TABLE tmp_display_values (id INT NOT NULL PRIMARY KEY, new_display_value INT);

INSERT
INTO    tmp_display_values
VALUES
(?, ?),
(?, ?),
…;

UPDATE  `table` dv
JOIN    tmp_display_values t
ON      dv.id = t.id
SET     dv.new_display_value = t.new_display_value;
...