У меня есть таблица 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 (!) этой конкретной синхронизации.
Есть ли место для улучшения?Сложный индекс?Что-нибудь еще?