mysql:强制不同的访问类型,在(…)中使用索引

siotufzp  于 2021-06-21  发布在  Mysql
关注(0)|答案(1)|浏览(319)

我正在尝试调整一个非常简单的查询:

  1. select * from log where user_id in (...) order by id desc limit 25

我只想显示一组不同用户id(大约40个id)的最后25个事件。这个查询大约需要50秒来运行(表中有超过8000万条记录)。
通过执行 EXPLAIN format=json 我看得出来 access_typerange . 经过一番探索,a了解到如果我将ID的数量更改为9,查询计划器将使用另一种访问方式: index .
所以我假设,对于大量的id,mysql将在组中较小的id和较大的id之间进行范围扫描,如果id是“close”,这可能是有意义的,但情况并非总是如此。也许在某种程度上,这个额外的数据量在进行排序时会成为一个问题(如下面的解释计划中所示)。
40身份证解释

  1. {
  2. "query_block": {
  3. "select_id": 1,
  4. "ordering_operation": {
  5. "using_filesort": true,
  6. "table": {
  7. "table_name": "log",
  8. "access_type": "range",
  9. "possible_keys": [
  10. "app_log_user_id"
  11. ],
  12. "key": "log_user_id",
  13. "used_key_parts": [
  14. "user_id"
  15. ],
  16. "key_length": "4",
  17. "rows": 6150,
  18. "filtered": 100,
  19. "index_condition": "(`app`.`log`.`user_id` in (<43 different ids from 12000 to 330000>))"
  20. }
  21. }
  22. }
  23. }

9 ID解释

  1. {
  2. "query_block": {
  3. "select_id": 1,
  4. "ordering_operation": {
  5. "using_filesort": false,
  6. "table": {
  7. "table_name": "log",
  8. "access_type": "index",
  9. "possible_keys": [
  10. "app_log_user_id"
  11. ],
  12. "key": "PRIMARY",
  13. "used_key_parts": [
  14. "id"
  15. ],
  16. "key_length": "4",
  17. "rows": 6901,
  18. "filtered": 4552.8,
  19. "attached_condition": "(`app`.`log`.`user_id` in (< 9 ids from 12000 to 18000))"
  20. }
  21. }
  22. }
  23. }

我做了一个实验:我将这个查询分成5个子查询,其中只有9个或更少的id,并应用了一个 UNION 对所有人来说,最后是命令和限制条款。这个查询的查询计划变得有点混乱,甚至有奇怪的值说其中一个子查询的搜索行数是86737713(我认为这是一个非常错误的估计,所有其他的都在10246左右)。你猜怎么着?查询只花了6秒,比50秒要好。
我不知道使用哪种策略来优化这种查询,但据我所知,如果我能告诉优化器使用 acess_typeindex 相反 range ,它会表现得更好。有可能吗?
额外细节 user_id 有外键和索引。
我们使用MySQL5.6(innodb)
表有大约80kk行。
显示创建表

  1. CREATE TABLE `app_log` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT,
  3. `timestamp` datetime NOT NULL,
  4. `user_id` int(11) NOT NULL,
  5. `content_type_id` int(11) NOT NULL,
  6. `object_id` int(10) unsigned NOT NULL,
  7. `status` int(11) DEFAULT NULL,
  8. `type` int(11) DEFAULT NULL,
  9. PRIMARY KEY (`id`),
  10. KEY `app_log_content_type_id` (`content_type_id`),
  11. KEY `app_log_144dd2a9` (`timestamp`),
  12. KEY `app_log_user_id` (`user_id`, `id`)
  13. )
  14. ENGINE = InnoDB
  15. AUTO_INCREMENT = 108628300
  16. DEFAULT CHARSET = latin1
relj7zay

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之间的区别)等等,出于所有实际目的,在本论坛中都可以忽略。

相关问题