【发布时间】:2018-12-12 04:33:35
【问题描述】:
我有一个包含数百万条记录的 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;
总共有大约 15 万条记录,其中 sync_log_uuid = 56b0a3b1-dab4-4343-9f9b-a2a8f075c21a。如果没有order by,则需要几毫秒才能给我第一条100 记录。
当我如上所示添加 order by 时,它会减慢到 30-45 秒。
我知道,我知道。我做了一项研究,我完全理解:
当我在没有 ORDER BY - LIMIT 100 的情况下运行查询时,它可以完美运行 - 它 在前 100 条记录后停止查询,任何 100 条记录
但是
当我添加 ORDER BY 时,MySQL 首先将 所有记录 发送到临时 表,然后对其进行排序,然后返回给我100条正确记录
这绝对是有道理的。在庞大的数据集上,它按预期工作。但是我已经到了不知道如何优化它的地步。我无法缩小日期 (exception_time),因为所有 log lines 的 UUID 都在 2 小时内插入 - 这是大约。同步时间。
我的查询用作分页的一部分,有时用户必须查看此特定同步的页面 212 (!)。
还有改进的余地吗?综合指数?还有什么?
【问题讨论】:
-
pagination,或许以exception_time为起点
WHERE exception_time > {prev value} LIMIT 100