Нужны некоторые рекомендации для оптимизации отчетности в MySQL - PullRequest
0 голосов
/ 23 января 2019

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

  • Отправка уведомлений контактам для различных кампаний
  • Запись идентификатора контакта, кампании, идентификатора сообщения, созданного, обновленного в журнал при отправке уведомления
  • Считайте количество записей для каждого параметраIDID /tification_messageID и отобразите его для пользователя в отчете.

Процесс записи и чтения в журнал занимает исключительно много времени, и мы ищем способ его оптимизации.

Оператор записи возникает при отправке уведомления. Пакетная вставка для 20 записей в одном запросе. Вот пример:

INSERT INTO `contact_notification_logs` (`id`, `contact_id`, `campaign_id`, 
`message_id`, `created_at`, `updated_at`, `is_reset`) 
VALUES 
(NULL, '1', '1', '1', '2019-01-23 20:16:21', '2019-01-23 20:16:24', 
'0'),

Существует два оператора чтения:

  1. Это довольно просто, оно запускается на странице, где перечислены все кампании, и отображает текущее количество уведомлений, отправленных на СЕГОДНЯ:
SELECT COUNT(id) FROM contact_notification_logs 
WHERE DATE(created_at) = '[current date]'

Этот, хотя и простой, все еще требует много времени для выполнения.

  1. Второй оператор чтения немного сложнее, поскольку он встроен в инструмент создания отчетов в приложении, где пользователи могут указывать параметры, но корень «счетчик выбора» тот же.

Вот пример:

SELECT COUNT(id) FROM contact_email_logs 
WHERE DATE(created_at) > '2018-12-23'
AND DATE(created_at) < '2019-01-23'
AND campaign_id = 27
AND message_id = 133

Пара дополнительных очков:

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

  2. В contact_notification_logs содержится 28 740 585 записей.

Я что-то упускаю здесь, что позволит нам оптимизировать время выполнения для этих запросов?

Ответы [ 2 ]

0 голосов
/ 26 января 2019

Неэффективный диапазон дат приводит к проверке слишком большого количества строк

WHERE DATE(created_at) > '2018-12-23'
  AND DATE(created_at) < '2019-01-23'
  AND campaign_id = 27
  AND message_id = 133

Не пишите сравнения дат таким способом.Он не может использовать индекс, включающий created_at, потому что он скрыт в вызове функции (DATE()).Вместо этого:

WHERE created_at >= '2018-12-23'
  AND created_at  < '2018-12-23' + INTERVAL 1 MONTH

Если этот материал DATE() сгенерирован сторонним пакетом, вам нужно отказаться от него.

Отсутствие подходящего индекса

Тогда ... вам нужен составной индекс:

INDEX(campaign_id, message_id,   -- in either order
      created_at)                -- after those

Для просто "сегодня"

SELECT COUNT(*) FROM contact_notification_logs 
    WHERE created_at >= '[current date]'
      AND created_at  < '[current date]' + INTERVAL 1 DAY

INDEX(created_at)  -- the previous index will not help for _this_ query

Нужна сводная таблица

С 28M строк, вы можете обнаружить, что мои предложения выше не являются достаточными.Чтобы получить еще 10-кратное улучшение, создайте и поддерживайте сводную таблицу .Предложите использовать дни, а не недели или месяцы в качестве разрешения.

Другие

Не используйте COUNT(id), если вам не нужно проверить, является ли id NULL.Вместо этого используйте общий шаблон: COUNT(*).

Если created_at имеет тип DATE, исходный запрос составляет один месяц, минус один день.Если это DATETIME, то отсутствует полночь начальной даты.С моим кодом он работает правильно независимо от типа данных.

Для дальнейшего обсуждения, пожалуйста, предоставьте SHOW CREATE TABLE.

0 голосов
/ 23 января 2019

для первого запроса на чтение: Есть ли у вас индекс по полю созданного?

для второго запроса на чтение: Есть ли у вас индекс, основанный на трех полях: create_at, campaign_id и message_id?

Если нет, взгляните на https://dev.mysql.com/doc/refman/5.5/en/create-index.html

...