我正在尝试调整一个非常简单的查询:
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之间进行范围扫描,如果id是“close”,这可能是有意义的,但情况并非总是如此。也许在某种程度上,这个额外的数据量在进行排序时会成为一个问题(如下面的解释计划中所示)。
40身份证解释
{
"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
对所有人来说,最后是命令和限制条款。这个查询的查询计划变得有点混乱,甚至有奇怪的值说其中一个子查询的搜索行数是86737713(我认为这是一个非常错误的估计,所有其他的都在10246左右)。你猜怎么着?查询只花了6秒,比50秒要好。
我不知道使用哪种策略来优化这种查询,但据我所知,如果我能告诉优化器使用 acess_type
的 index
相反 range
,它会表现得更好。有可能吗?
额外细节 user_id
有外键和索引。
我们使用MySQL5.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
1条答案
按热度按时间relj7zay1#
可能的解释是:
您使用的是哪个版本的mysql/mariadb?我猜你用的是MySQL5.6(你使用
FORMAT=JSON
确认“至少5.6.5”。)5.6.5介绍
eq_range_index_dive_limit
,默认值为10。5.7.4
eq_range_index_dive_limit
默认值提高到200-影响IN()
可能的解决方法:这张便条可能解释了你的9对43项中
IN
列表。建议你和我一起玩eq_range_index_dive_limit
.琐事
kk=千
m、 对会计师来说,千等于千
嗯,对会计师来说是百万,一个拉卡
10万,印第安人=10万
百万印度卢比=1000万(1000万)
十亿,对英国人来说曾经是百万;幸运的是,这种困惑似乎已经消失。
1000和1024之间的区别(以及kb和kib之间的区别)等等,出于所有实际目的,在本论坛中都可以忽略。