MySQL:在大型表上的查询非常慢,并按时间戳顺序排序(尽管有索引)…

时间:2018-12-12 04:33:35

标签: mysql sql

我有一个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小时内插入-这大约是2小时。同步时间。

我的查询被用作分页的一部分,有时在某些情况下,用户必须查看此特定同步的页面 212(!)

还有改进的空间吗?综合指数?还有吗?

2 个答案:

答案 0 :(得分:3)

在sync_log_uuid和exception_time上都创建1个索引。

CREATE INDEX my_index ON sync_log_lines (sync_log_uuid, exception_time);

如果您不进行ORDER BY,查找MySQL的前100条记录将很快完成,因为它可以返回找到的前100条记录。

如果您要按例外时间订购,则MySQL必须读取其中sync_log_uuid ='56b0a3b1-dab4-4343-9f9b-a2a8f075c21a'的所有记录,以确定哪些记录是前100条。

答案 1 :(得分:0)

尝试使用复合索引也称为多列索引。它将提供更好的性能。如上述回答创建索引 http://www.mysqltutorial.org/mysql-index/mysql-composite-index/