【发布时间】:2018-12-18 16:58:47
【问题描述】:
我正在尝试调整一个非常简单的查询:
select * from log where user_id in (...) order by id desc limit 25
我只想显示一组不同用户 ID(大约 40 个 ID)的最后 25 个事件。此查询大约需要 50 秒才能运行(表中的记录超过 8000 万条)。
通过执行EXPLAIN format=json,我可以看到access_type 是range。经过一番探索,a了解到如果我将ID数改为9,查询规划器将使用另一种访问方式:index。
所以我假设对于大量 ID,MySQL 将在组的较小和较大 id 之间进行范围扫描,如果 ID 是“接近”的,这可能是有意义的,但情况并非总是如此。也许不知何故,这些额外的数据量在进行排序时会成为一个问题(如下面的解释计划所示)。
40 个 ID 解释
{
"query_block": {
"select_id": 1,
"ordering_operation": {
"using_filesort": true,
"table": {
"table_name": "log",
"access_type": "range",
"possible_keys": [
"app_log_user_id"
],
"key": "log_user_id",
"used_key_parts": [
"user_id"
],
"key_length": "4",
"rows": 6150,
"filtered": 100,
"index_condition": "(`app`.`log`.`user_id` in (<43 different ids from 12000 to 330000>))"
}
}
}
}
9 个 ID 解释
{
"query_block": {
"select_id": 1,
"ordering_operation": {
"using_filesort": false,
"table": {
"table_name": "log",
"access_type": "index",
"possible_keys": [
"app_log_user_id"
],
"key": "PRIMARY",
"used_key_parts": [
"id"
],
"key_length": "4",
"rows": 6901,
"filtered": 4552.8,
"attached_condition": "(`app`.`log`.`user_id` in (< 9 ids from 12000 to 18000))"
}
}
}
}
我做了一个实验:我将该查询分为 5 个其他子查询,只有 9 个或更少的 ID,并对所有子查询应用 UNION,最后使用 ORDER 和 LIMIT 子句。这个查询的查询计划变得有点混乱,即使有奇怪的值表明其中一个子查询的搜索行数是 86737713(我认为这是一个非常错误的估计,其他的都在 10246 左右)。你猜怎么了?查询“仅”用了 6 秒,比 50 秒好。
我不知道使用哪些策略来优化这种查询,但据我所知,如果我可以告诉优化器使用index 的acess_type 代替range,它会表现更好。这可能吗?
额外细节
-
user_id有一个外键和一个索引。 - 我们使用 MySQL 5.6 (InnoDB)
- 表格有大约 80kk 行。
显示创建表
CREATE TABLE `app_log` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`timestamp` datetime NOT NULL,
`user_id` int(11) NOT NULL,
`content_type_id` int(11) NOT NULL,
`object_id` int(10) unsigned NOT NULL,
`status` int(11) DEFAULT NULL,
`type` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `app_log_content_type_id` (`content_type_id`),
KEY `app_log_144dd2a9` (`timestamp`),
KEY `app_log_user_id` (`user_id`, `id`)
)
ENGINE = InnoDB
AUTO_INCREMENT = 108628300
DEFAULT CHARSET = latin1
【问题讨论】:
-
请提供
SHOW CREATE TABLE log;有什么腥味。列表中的 id 是数字还是字符串;是不带引号还是带引号? -
请在 CREATE TABLE 中包含索引。另外,看看覆盖索引是否有帮助:dba.stackexchange.com/questions/36705/…
-
@RickJames 我添加了表定义。 ID 是数字,不涉及引号。
-
单位的
kk是什么? -
@N.B.这应该意味着数百万(我想非常非正式,我还是修好了)。
标签: mysql sql indexing innodb database-indexes