MySQL: очень медленный запрос к огромной таблице с упорядочением по отметке времени (несмотря на наличие индексов)… - PullRequest
0 голосов
/ 12 декабря 2018

У меня есть таблица sync_log_lines с миллионами записей.

CREATE TABLE `sync_log_lines` (
  `uuid` char(36) COLLATE utf8mb4_unicode_ci NOT NULL,
  `sync_log_uuid` char(36) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `exception_time` timestamp NULL DEFAULT NULL,
  `exception_message` mediumtext COLLATE utf8mb4_unicode_ci,
  `exception_file` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `exception_line` int(10) unsigned DEFAULT NULL,
  `failure_reason` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `csv_file_row_count` int(10) unsigned DEFAULT NULL,
  `csv_file_row_sequence` int(10) unsigned DEFAULT NULL,
  `csv_file_row_content` mediumtext COLLATE utf8mb4_unicode_ci,
  `csv_file_source` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`uuid`),
  KEY `sync_log_lines_sync_log_uuid_index` (`sync_log_uuid`),
  KEY `sync_log_lines_exception_time_index` (`exception_time`),
  CONSTRAINT `sync_log_lines_sync_log_uuid_foreign` FOREIGN KEY (`sync_log_uuid`) REFERENCES `sync_logs` (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Одна операция «синхронизация» может вставить 150k записей в эту таблицу.Каждая запись в sync_log_lines - это отдельная строка CSV, которую не удалось вставить или обновить в выделенной таблице.

Поэтому приведенный ниже запрос может быстро возрасти.

select `uuid`, `sync_log_uuid`, `exception_time`, `exception_message`, `failure_reason`, `csv_file_row_count`, `csv_file_row_sequence`, `csv_file_row_content` 
from `sync_log_lines` 
where `sync_log_uuid` = '56b0a3b1-dab4-4343-9f9b-a2a8f075c21a' 
order by `exception_time` desc 
limit 100 offset 6000;

Общее количество записей ~ 150k, где sync_log_uuid = 56b0a3b1-dab4-4343-9f9b-a2a8f075c21a.Без order by для получения первых 100 записей требуются миллисекунды.

Когда я добавляю order by, как показано выше, он замедляется до 30-45 секунд.

Я знаю, язнать.Я провел исследование и полностью понимаю, что:

, когда я запускаю запрос без ORDER BY - LIMIT 100, он отлично работает - останавливает запрос после первых 100 записей, любой 100записи

но

когда я добавляю ORDER BY, MySQL сначала отправляет все записи во временную таблицу, , затем сортирует itа потом возвращает мне 100 правильных записей

Это абсолютно имеет смысл.На огромном наборе данных это работает как ожидалось.Но я дошел до того, что не знаю, как его оптимизировать.Я не могу сузить даты (exception_time), поскольку все log lines для этого UUID вставляются в течение 2 часов - это прибл.время синхронизации.

Мой запрос используется как часть нумерации страниц, и иногда возникает случай, когда пользователь должен увидеть страницу 212 (!) этой конкретной синхронизации.

Есть ли место для улучшения?Сложный индекс?Что-нибудь еще?

Ответы [ 2 ]

0 голосов
/ 12 декабря 2018

Попробуйте использовать составной индекс, также известный как многостолбцовый индекс.Это даст лучшую производительность.Как упомянуто в ответе выше для создания индекса http://www.mysqltutorial.org/mysql-index/mysql-composite-index/

0 голосов
/ 12 декабря 2018

Создайте 1 индекс для sync_log_uuid и exception_time.

CREATE INDEX my_index ON sync_log_lines (sync_log_uuid, exception_time);

Найти первые 100 записей быстро для MySQL, если вы не ORDER BY, потому что он может просто вернуть первые 100 найденных записей.

Если вы заказываете по исключению, MySQL должен прочитать все записи где sync_log_uuid = '56b0a3b1-dab4-4343-9f9b-a2a8f075c21a', чтобы определить, какие из них являются первыми 100.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...