очень счастлив! Наконец-то ступил на яму медленного запроса

MySQL

Я читал блог, написанный командой Ele.me раньше: подождите! Мы прошли эти две ямы Spring-RabbitMQ за вас. Глубоко вдохновившись, вы должны выбрать заголовок, способный привлечь внимание читателей.Конечно, помимо известного заголовка, содержание должно быть еще и сухим. Почему вы хотите взять такое название, потому что сегодня я видел теоретическую медленную оптимизацию запросов! ! ! Наконец-то в производстве

(1) Медленный sql один

поиск проблемы

После того, как приложение выпущено в производственную среду, интерфейсная страница запрашивает внутренний API для возврата данных, и выясняется, что это занимает не менее 6 секунд. Проверьте медленный sql:慢sql定位.png

Воспроизвести медленный sql

Выполнить sql:

select count(*) from sync_block_data
where unix_timestamp(sync_dt) >= 1539101010
AND unix_timestamp(sync_dt) <= 1539705810

Просмотр занимает много времени:慢查询耗时.pngОбщее время — 2658 мс.
Посмотреть план выполнения:

explain select count(*) from sync_block_data
where unix_timestamp(sync_dt) >= 1539101010
AND unix_timestamp(sync_dt) <= 1539705810

Результаты выполнения плана:慢查询执行计划.png

Оптимизировать медленный sql one

Тип sync_dt — это тип даты и времени. Другой способ написания SQL — сравнение дат напрямую, а не временных меток. Преобразуйте метку времени в sql на сегодняшний день, 2018-10-10 00:03:30 и 2018-10-17 00:03:30 соответственно.
Выполнить sql:

select count(*) from sync_block_data
where sync_dt >= "2018-10-10 00:03:30"
AND sync_dt <= "2018-10-17 00:03:30"

Просмотр занимает много времени:快查询耗时.pngВ общей сложности это заняло 419 миллисекунд, что более чем в шесть раз быстрее, чем медленные запросы.
Посмотреть план выполнения:

explain select count(*) from sync_block_data
where sync_dt >= "2018-10-10 00:03:30"
AND sync_dt <= "2018-10-17 00:03:30"

Результаты выполнения плана:快查询执行计划.pngПосещение страницы, среднее время запроса после оптимизации составляет 900 миллисекунд.image.png

Единственная разница между медленным запросом и быстрым запросом в плане выполнения заключается в том, что тип отличается: тип медленного запроса — индекс, а тип быстрого запроса — диапазон.

Оптимизировать медленный запрос 2

Бизнес-логика этого sql заключается в подсчете объема данных таблицы за последние семь дней, вы можете удалить меньше или равно справа
Выполнить sql:

select count(*) from sync_block_data
where sync_dt >= "2018-10-10 00:03:30"

Просмотр занимает много времени:image.pngВ общей сложности это заняло 275 миллисекунд, что сократило время запроса вдвое.
Посмотреть план выполнения:

explain select count(*) from sync_block_data
where sync_dt >= "2018-10-10 00:03:30"

Результаты выполнения плана:image.pngтип все еще диапазон. Но удваивает скорость запроса с одним сравнением меньше

Оптимизация медленного запроса 3

Создайте новое поле типа bigint sync_dt_long для хранения миллисекундного значения sync_dt и создайте индекс для поля sync_dt_long.
В тестовой среде:
Оптимизировать медленный запрос два sql

select count(*) from copy_sync_block_data
where sync_dt >="2018-10-10 13:15:02"

Занимает 34 миллисекунды
Оптимизировать медленный запрос три sql

select count(*) from copy_sync_block_data
where sync_dt_long >= 1539148502916

Занимает 22 миллисекунды
В тестовой среде скорость увеличилась примерно на 10 миллисекунд.

Оптимизация медленного запроса три сводки теста sql: в механизме хранения InnoDB эффективность сравнения bigint выше, чем datetime
После завершения трехэтапной оптимизации время запроса в производственной среде:image.pngЭто снова примерно на 200 мс быстрее. При добавлении 10-секундного кэша к запрашиваемым данным скорость ответа становится самой высокой, а среднее значение составляет 20 мс.

Введение в использование объяснения

С помощью объяснения вы можете просмотреть выполнение оператора sql (например, запрошенную таблицу, используемый индекс и способ, которым mysql находит нужную строку в таблице и т. д.).
Выходные параметры использования объяснения для запроса плана запроса mysql:

имя столбца инструкция
id Номер выполнения идентифицирует строку, к которой принадлежит выбор. Если в операторе нет подзапросов или связанных запросов, а есть только один выбор, в каждой строке будет отображаться 1. В противном случае внутренний оператор select обычно нумеруется последовательно, в соответствии с его позицией в исходном операторе.
select_type Показывает, является ли эта строка простой или сложной выборкой. Если запрос содержит какие-либо сложные подзапросы, самый внешний уровень помечается как ОСНОВНОЙ (ПРОИЗВОДНЫЙ, ОБЪЕДИНЕНИЕ, РЕЗУЛЬТАТ ОБЪЕДИНЕНИЯ).
table доступ к таблице, на которую ссылаются (ссылаясь на такой запрос, как "derived3")
type Тип операции доступа/чтения данных (ALL, index, range, ref, eq_ref, const/system, NULL)
possible_keys Узнайте, какие индексы могут быть полезны для эффективного поиска
key Показывает, какой индекс mysql использует для оптимизации запроса.
key_len Отображает количество байтов, используемых mysql в индексе
ref Показывает столбец или константу, используемую предыдущей таблицей для поиска значения в индексе записи ключевого столбца.
rows Количество строк, которые нужно прочитать, чтобы найти нужную строку, оценка неточная. Перемножая все значения столбцов строк вместе, вы можете получить приблизительную оценку количества строк, которые будет проверять весь запрос.
Extra Дополнительная информация, такая как использование индекса, сортировка файлов и т. д.

Сосредоточьтесь на типе, разница в типе на самом деле приводит к ухудшению производительности в шесть раз! ! !

type показывает тип доступа, что является более важным показателем.Результирующие значения от хорошего к плохому таковы: system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL , Вообще говоря, необходимо убедиться, что запрос достигает как минимум уровня диапазона, предпочтительно ref.

тип инструкция
All В худшем случае полное сканирование таблицы
index То же, что и полное сканирование таблицы. Просто сканируйте таблицу в порядке индекса, а не в строке. Основное преимущество состоит в том, что сортировки не требуется, но накладные расходы остаются очень высокими. Если вы видите Использование индекса в столбце Дополнительно, это означает, что используется покрывающий индекс, и сканируются только проиндексированные данные, что намного дешевле, чем полное сканирование таблицы в порядке индексов.
range Сканирование диапазона, ограниченное сканирование индекса. Ключевой столбец показывает, какой индекс использовался. При сравнении столбцов ключевых слов с константами с помощью операторов =, , >, >=, , BETWEEN или IN можно использовать диапазон
ref Индексированный доступ, который возвращает все строки, соответствующие одному значению. Такой доступ к индексу происходит только тогда, когда используется неуникальный индекс или уникальный неуникальный префикс индекса. Этот тип отличается от eq_ref тем, что он используется в операциях ассоциации, которые используют только крайний левый префикс индекса, либо индекс не является UNIQUE и PRIMARY KEY. ref можно использовать для индексированных столбцов с помощью операторов = или .
eq_ref Возвращается не более одной совпадающей записи. Возникает при использовании поиска по уникальному индексу или первичному ключу (эффективно)
const Когда определено, что совпадет не более одной строки, оптимизатор MySQL прочитает ее перед запросом и только один раз, поэтому это очень быстро. Когда первичный ключ помещается в предложение where, mysql преобразует запрос в константу (эффективную)
system Это частный случай константного соединения, когда только одна строка таблицы удовлетворяет условию.
Null Это означает, что mysql может разложить оператор запроса на этапе оптимизации и даже не должен обращаться к таблице или индексу на этапе выполнения (эффективно).

Причины медленных запросов

Функциональная операция используется в предложении where
Функция unix_timestamp используется в операторе SQL с медленным запросом для подсчета разницы в секундах от «1970-01-01 00:00:00» до текущего времени. Вызывает полное сканирование индекса для подсчета объема данных за последние семь дней.

решение

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

постскриптум

Эта проблема не была обнаружена в тестовой среде в то время, и скорость запросов тестовой среды все еще была приемлемой. Не быть найденным сводится к количеству данных. Объем производственных данных находится на уровне миллионов, а объем данных тестовой среды — на уровне 10 000. Объем данных в 50 раз хуже.Увеличение объема данных также усугубляет проблему медленных запросов.

(2) Медленный SQL II

Поскольку существует очевидная проблема медленного ответа на запрос в Интернете, я пошел посмотреть другие sql в проекте и обнаружил, что эффективность выполнения sql относительно низкая.

Воспроизвести медленный sql

выполнить sql

select FROM_UNIXTIME(copyright_apply_time/1000,'%Y-%m-%d') point,count(1) nums
from resource_info where copyright_apply_time >= 1539336488355 and copyright_apply_time <= 1539941288355 group by point

Просмотр занимает много времени:image.pngПотребовалось 1123 миллисекунды Посмотреть план выполнения:

explain select FROM_UNIXTIME(copyright_apply_time/1000,'%Y-%m-%d') point,count(1) nums
from resource_info where copyright_apply_time >= 1539336488355 and copyright_apply_time <= 1539941288355 group by point

Результаты выполнения плана:image.pngИндекс срабатывает, но в дополнительном поле отображаются «Использование временных файлов» и «Использование файловой сортировки».

Оптимизировать медленный sql one

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

select FROM_UNIXTIME(copyright_apply_time/1000,'%Y-%m-%d') point,count(1) nums
from resource_info where copyright_apply_time >= 1539336488355 and copyright_apply_time <= 1539941288355 group by point order by null

Просмотр занимает много времени:image.pngВсего потребовалось 1068 миллисекунд, увеличение примерно на 100 миллисекунд, эффект не особенно заметен.
Посмотреть план выполнения:image.pngВ дополнительном поле нет пункта Использование сортировки файлов, а сортировка файлов означает сортировку возвращаемых данных. Все сортировки, которые не возвращают результаты сортировки напрямую через индекс, являются сортировкой FileSort, что указывает на то, что результаты сортировки возвращаются напрямую через индекс после оптимизации. Использование временных по-прежнему существует. Возникновение использования временных означает, что запрос использует временную таблицу, что обычно происходит в случае сортировки, группировки и объединения нескольких таблиц. Эффективность запроса не высока и все еще нуждается в оптимизации. Причина для временной таблицы здесь заключается в том, что объем данных слишком велик для использования.Группировка операций во временной таблице

Оптимизировать медленный sql два

Бизнес-логика медленного запроса SQL заключается в подсчете количества каждого периода времени в пределах диапазона условий в соответствии с классификацией периода времени.
Например, если заданный диапазон условий представляет собой отметку времени 2018-10-20~2018-10-27, этот sql будет считать приращение данных 2018-10-20~2018-10-27 каждый день. Теперь оптимизировано проверять каждый день, проверять данные семь раз по отдельности и убирать операцию группировки

select FROM_UNIXTIME(copyright_apply_time/1000,'%Y-%m-%d') point,count(1) nums
from resource_info where copyright_apply_time >= 1539855067355 and copyright_apply_time <= 1539941467355 

Просмотр занимает много времени:image.pngЗатратное время составляет 38 миллисекунд, даже если он проверяется 7 раз, время составляет менее 1123 миллисекунд.
Посмотреть план выполнения:image.pngПо сравнению с дополнительным медленным запросом, Использование временных файлов и Использование сортировки файлов меньше в дополнительном поле. Идеально

Таким образом, я впервые испытал настоящий медленный запрос и оптимизацию медленного запроса и, наконец, объединил теорию и практику.