按 id 排序的复合索引上的并发查询非常慢
Posted
技术标签:
【中文标题】按 id 排序的复合索引上的并发查询非常慢【英文标题】:Concurrent queries on composite index with order by id drastically slow 【发布时间】:2018-05-07 03:45:18 【问题描述】:我有一个表定义如下:
| book | CREATE TABLE `book` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`provider_id` int(10) unsigned DEFAULT '0',
`source_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`description` longtext COLLATE utf8_unicode_ci,
PRIMARY KEY (`id`),
UNIQUE KEY `provider` (`provider_id`,`source_id`),
KEY `idx_source_id` (`source_id`),
) ENGINE=InnoDB AUTO_INCREMENT=1605425 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
当有大约 10 个并发读取时使用以下 sql:
SELECT * FROM `book` WHERE (provider_id = '1' AND source_id = '1037122800') ORDER BY `book`.`id` ASC LIMIT 1
它变慢了,大约需要 100 毫秒。
但是如果我把它改成
SELECT * FROM `book` WHERE (provider_id = '1' AND source_id = '221630001') LIMIT 1
那么就正常了,需要几个ms。
我不明白为什么按 id 添加订单会使查询变慢?谁能解释一下?
【问题讨论】:
首先,你的查询条件不同。如果您想将一件事与另一件事进行比较,请不要更改它们。现在它可能与排序无关,而与条件有关。其次,如果您想要任何单个结果,数据库可以按任何顺序运行,并在找到一个后停止。如果您对它进行排序,它必须找到特定的,并且可能必须遍历所有数据。 100ms也很慢?取决于数据量。检查查询计划。 @SamiKuhmonen,在海量查询条件下,source_id 没有区别。在这两种情况下(无论是否按 id 排序)的单个查询中,只需要几个毫秒。 提示 1:不要将字符串与整数进行比较 @Strawberry,我把“provider_id = '1'”改成“provider_id = 1”,结果是一样的,应该是mysql优化的吧。 如果反转 provider_id,source_id 索引会发生什么?此外,鉴于此索引是唯一的,order by(和 limit)子句似乎没有任何作用 【参考方案1】:尝试添加所需的列(选择列名,..)而不是 * 或参考这个。
Why is my SQL Server ORDER BY slow despite the ordered column being indexed?
【讨论】:
【参考方案2】:我不是 mysql 专家,无法进行详细分析,但我的猜测是,因为您在 WHERE
子句中为 UNIQUE KEY
提供值,引擎可以去获取它直接使用索引行。
但是,当您向ORDER BY
询问id
列(即PRIMARY KEY
)时,会更改访问路径。引擎现在猜测,由于它在id
上有一个索引,并且您想按id
排序,因此最好以PK 顺序获取该数据,这样可以避免排序。但是,在这种情况下,它会导致结果变慢,因为它必须将每一行与标准进行比较(表扫描)。
请注意,这只是推测。你需要EXPLAIN
这两个语句才能看到发生了什么。
【讨论】:
解释结果完全一样,只扫描了一行。我猜这个问题可能与表锁有关。以上是关于按 id 排序的复合索引上的并发查询非常慢的主要内容,如果未能解决你的问题,请参考以下文章