mysql解释类型索引与所有性能问题

Posted

技术标签:

【中文标题】mysql解释类型索引与所有性能问题【英文标题】:mysql explain type index vs all performance question 【发布时间】:2020-12-23 15:45:47 【问题描述】:

我有下表:我有 350 万条记录。

CREATE TABLE `video_downloads` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NOT NULL,
  `video_id` bigint(20) NOT NULL,
  `download_at` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3573041 DEFAULT CHARSET=latin1

只有iduser_idindexed

这是我的查询:

select max(video_id), user_id
from video_downloads
group by user_id

使用当前的表设置,我运行了这个查询大约需要 10 多分钟。 所以这里是explain

| id | select_type | table           | type  | possible_keys | key     | key_len | ref | rows    | Extra |
|----|-------------|-----------------|-------|---------------|---------|---------|-----|---------|-------|
| 1  | SIMPLE      | video_downloads | index |               | user_id | 8       |     | 3562709 |       |

  "query_block": 
    "select_id": 1,
    "table": 
      "table_name": "video_downloads",
      "access_type": "index",
      "key": "user_id",
      "key_length": "8",
      "used_key_parts": ["user_id"],
      "rows": 3562709,
      "filtered": 100
    
  

然后我删除了运行相同查询的user_id 的索引,我花了大约1.5 s

这是没有user_id索引的explain

| id | select_type | table           | type | possible_keys | key | key_len | ref | rows    | Extra                           |
|----|-------------|-----------------|------|---------------|-----|---------|-----|---------|---------------------------------|
| 1  | SIMPLE      | video_downloads | ALL  |               |     |         |     | 3562709 | Using temporary; Using filesort |

  "query_block": 
    "select_id": 1,
    "filesort": 
      "sort_key": "video_downloads.user_id",
      "temporary_table": 
        "table": 
          "table_name": "video_downloads",
          "access_type": "ALL",
          "rows": 3562709,
          "filtered": 100
        
      
    
  

我认为我的主要问题是为什么在 user_id 上使用和不使用索引的时间方面存在如此巨大的差异。当user_id 上有索引时,typeindex,这意味着它正在使用索引但查询很慢。

我对结果有点困惑我想我不明白为什么会这样,我检查了official doc 仍然不完全明白。

更新 我认为主要原因可能是它使用index 数据从磁盘获取行,并且它会一一随机地进行。所以这是从磁盘随机读取的 350 万次。这是我能想到的唯一原因。然而,这会那么慢吗? (超过10 mins vs 1.5 s ???)。

但是,来自mysql doc

有时 MySQL 不使用索引,即使索引可用。发生这种情况的一种情况是优化器估计使用索引将需要 MySQL 访问表中很大比例的行。

就我而言,MySQL 似乎没有做出正确的决定。我可以看到possible_keysnullkey 仍在使用索引,为什么?是因为group by吗?

【问题讨论】:

我对这些计划有点困惑。他们似乎没有进行聚合。 @GordonLinoff 任何帮助或建议将不胜感激。还是我需要提供更多信息? 在图片中提供信息而不是使用纯文本总是很烦人。 请提供SHOW CREATE TABLE;当您尝试简化表定义时,有太多微妙的问题被遗漏了。 是 I/O 绑定;我更新了我的答案以部分解释它。该表大约 300MB,对吗? 【参考方案1】:

优化器使用的“统计数据”并不总是完美的。然而,“10 分钟”与“1.5 秒”的对比相当壮观。我想知道是否有外部干扰。哦,正在使用什么引擎?

当它使用单列索引时,它可能不得不在索引和数据之间来回切换,一次获取 350 万行,但是是随机的。

当它进行表扫描(“全部”)时,它还读取了 350 万行,但是是按顺序读取的。但随后它必须进行排序。

Buffer_pool

innodb_buffer_pool_size 的 16M 是问题所在。除非您的机器特别小,否则请将其设置为 RAM 大小的 70% 左右。

10 分钟的查询可能是可靠的 I/O,从表中读取和重新读取数据随机

在旋转磁盘(HDD,而不是 SDD)上,以 100 块/秒的速度读取 350 万次数据需要几个小时。所以你很幸运在 10 分钟内完成。 1.5s 说明了足够大的 RAM 缓存是多么有用。

只需 1.5 秒就可以直接(不是随机)阅读整个表格一次。

【讨论】:

我已经更新了我的问题,你知道为什么会这样吗? @AndySong - 唉,没有明显的解释。还有一个问题:SHOW VARIABLES LIKE 'innodb_buffer_pool_size; 'innodb_buffer_pool_size'16777216 @AndySong - 就是这样。什么版本?多少内存?我添加到我的答案中。 INDEX(user_id, video_id) 应该运行得更快。

以上是关于mysql解释类型索引与所有性能问题的主要内容,如果未能解决你的问题,请参考以下文章

使用 Using temporary 解释 mysql 性能中的计划;使用文件排序;使用索引条件

高性能mysql 第4章 Schema与数据类型优化

高性能MySQL-第五章创建高性能的索引

MySQL索引优化-性能分析Explain(转)

创建高性能的索引

高性能MySQL——创建高性能的索引