MySQL запросов очень медленно - иногда - PullRequest
1 голос
/ 30 апреля 2020

Я использую MariaDB 10.2.31 на Ubuntu 18.4.4 LTS. На регулярной основе я сталкиваюсь со следующей загадкой - особенно когда начинаю работу утром, то есть, когда моя среда DEV неактивна в течение ночи - но также время от времени днем.

У меня есть таблица (это относится и к другим таблицам) с ок. 15.000 строк и (среди прочего) индекс столбца VARCHAR, содержащий в среднем от 5 до 10 символов. Примечательно, что большинство столбцов, включая этот, являются GENERATED ALWAYS AS (JSON_EXTRACT(....)) STORED, поскольку 99% моих данных поступает из REST API в виде JSON -кодированных строк (и для удобства я просто храню их в одном столбце и извлекаю все остальное).

При выполнении запроса к этому столбцу WHERE colname LIKE 'text%' Я считаю, что длительность запроса составляет, например, 0,006 секунды. Ницца. Когда у меня есть запрос EXPLAIN ed, я вижу, что индекс используется. Однако, как я уже говорил, когда я начинаю утром, это занимает больше времени (14 секунд сегодня утром). Я знаю о кеше запросов, и я попытался сделать это с отключенным кешем запросов (через SET GLOBAL query_cache_type=OFF и RESET QUERY CACHE). В этом случае я получаю постоянное время ок. 0,3 секунды - как и ожидалось.

Итак, что бы вы посоветовали мне посмотреть? Моя БД спит? Есть ли такая вещь?

Ответы [ 3 ]

1 голос
/ 30 апреля 2020

Возможны две вещи:

1) Холодное кэширование (резервное копирование в течение ночи, перезапуск mysqld или большое задание на обработку приводят к тому, что этот конкретный индекс и данные таблицы удаляются из памяти).

2) Статистика в таблице go устарела, и планировщик запросов будет сбит с толку, пока вы не выполните некоторые запросы к таблице, и статистика не будет обновлена. Вы можете принудительно обновить обновление, используя ANALYZE TABLE table_name.

3) Планировщик запросов heisenbug. Очень часто встречается в MySQL 5.7 и более поздних версиях, никогда не видела его ранее на MariaDB, так что это маловероятно.

Вы можете найти в этом смысл, включив в конфигурацию следующее:

log_output='FILE'
log_slow_queries=1
log_slow_verbosity='query_plan,explain'
long_query_time=1

Затем просмотрите, что находится в медленном журнале, сразу после того, как вы видите медленное возникновение. Если зарегистрированный план объяснения выглядит одинаково как для медленных, так и для быстрых случаев, у вас есть проблема с холодным кэшированием. Если они различаются, у вас есть проблема со статистикой таблицы, и вам нужно выполнить cron ANALYZE TABLE в конце ночной задачи, которая много читает / пишет в эту таблицу. Если это не помогает, в крайнем случае, жестко закодируйте подсказку индекса в вашем запросе с помощью FORCE INDEX (index_name).

0 голосов
/ 30 апреля 2020

Кричите и спасибо всем, кто дает ценную информацию! Из всех советов, которые вы, ребята, дали, я думаю, что начинаю лучше понимать проблему и начинаю сужать ее:

Первое, что я нашел, было мое значение по умолчанию innodb_buffer_pool_size 134 МБ. Из-за сортировки и количества данных, которые я обрабатываю, это смехотворно мало - поэтому я смог увеличить их. Очень полезный пост: https://dba.stackexchange.com/a/27341 И из документов: https://dev.mysql.com/doc/refman/8.0/en/innodb-buffer-pool-resize.html

Теперь, когда я увеличил его до 2 ГБ и могу контролировать его использование и использование ОЗУ в целом (cli: cat / proc / meminfo) Я понимаю, что моя 4 ГБ ОЗУ на самом деле находится на низком уровне. Я нигде не вижу каких-либо неиспользованных служебных данных (использование буфера по-прежнему составляет 99%, а объем свободной оперативной памяти - около 100 МБ).

Далее я начну оптимизировать использование оперативной памяти моего демона и посмотрим, к чему это приведет - но это не освободит В целом достаточно оперативной памяти.

@ danblack упомянул innodb_buffer_pool_dump_now и innodb_buffer_pool_load_now. Это интересный подход, который можно использовать всякий раз, когда демон обращается к БД, поскольку я хотел бы отделить использование буфера моего демона от внешнего интерфейса (очевидно, это невозможно!). Я рассмотрю это далее, но, поскольку мой демон работает все время (не только ночью), это может оказаться невозможным.

@ Gordan Bobi c упомянул "обновление" DBtables с помощью ANALYZE TABLE tableName. Я обнаружил, что это довольно быстро, и включал его в демон после каждого расширенного чтения / записи. Это увеличивает время работы демона на несколько секунд, но это не проблема. И я полагаю, что не могу go ошибиться:)

Итак, в конце концов, я считаю, что моя проблема - это сочетание вещей: слишком маленький размер буфера, слишком маленький объем ОЗУ, слишком много чтения / операции записи для этой среды (исключение буферизованных индексов и т. д. c.). Также мне нужно будет больше узнать о распределении памяти et c и оптимизировать его лучше (large-pages = 1 et c).

0 голосов
/ 30 апреля 2020

Включите медленный журнал запросов с log_slow_verbosity=query_plan,explain и long_query_time, достаточным для получения результатов. Посмотрите, иногда ли он использует другой (или нет) индекс.

Прежде чем начать свой следующий день, посмотрите на SHOW GLOBAL STATUS LIKE "innodb_buffer_pool%", а после запроса снова посмотрите значения. Посмотрите, сколько операций чтения из пула буферов по сравнению с запросами на чтение находятся в этих выходных данных состояния, чтобы увидеть, все ли исходят с диска.

Как упоминалось в @Solarflare, резервные копии и ночные операции могут очищать буферный пул innodb кэшированных данных и возвращать их обратно. плохо на диск, чтобы сделать это снова медленно. Как часть вашей ночной активности вы можете установить innodb_buffer_pool_dump_now = 1 для сохранения горячих страниц до выполнения сценариев и innodb_buffer_pool_load_now = 1 для ее восстановления.

...