前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MySQL核心知识学习之路(5)

MySQL核心知识学习之路(5)

作者头像
Edison Zhou
修改2021-03-06 11:57:50
5260
修改2021-03-06 11:57:50
举报
文章被收录于专栏:EdisonTalkEdisonTalk

作为一个后端工程师,想必没有人没用过数据库,跟我一起复习一下MySQL吧,本文是我学习《MySQL实战45讲》的总结笔记的第五篇,总结了MySQL索引相关的实践使用问题。

上一篇:MySQL核心知识学习之路(4)

1 普通索引与唯一索引如何选择?

先说结论

查询性能对比上普通索引和唯一索引差别不大。

更新性能对比上普通索引可以使用Change Buffer机制提高性能(前提:在业务层面保证数据唯一)。唯一索引则每次都需要判断是否违反唯一约束,因此每次都需要从内存中找到对应数据页,如果不在内存中则需要从磁盘读取出来,因此效率较低。

因此,如果业务可以接受,从性能角度出发,建议优先考虑普通索引

关于Change Buffer机制

Change Buffer是一种特殊的数据结构,它的过程如下:

(1)在对数据变更时,如果数据所在的数据页不在内存中的话,就先将更新操作记录在Change Buffer中,不需要从磁盘中读出数据页。

(2)Change Buffer中的数据会最终更新到原数据页,这个操作称之为Merge。

MySQL中进行Merge操作的时机包括:

  • 当目标数据页加载到内存中的时候,会先执行Change Buffer中的Merge操作。
  • 系统后台线程会定期执行Merge操作。
  • MySQL正常关闭(shutdown)时也会执行Merge操作。

使用Change Buffer的优点在于:将数据页从磁盘中读入内存涉及随机IO访问,是数据库中成本最高的操作之一,Change Buffer可以有效减少随机IO读操作,从而提升性能

下图展示了一个带有Change Buffer的工作流程,假设我们向表t插入了两行记录,其中一行记录在Page1(已经在内存中),另一行记录在Page2(不在内存中,需要写入到磁盘)。

代码语言:javascript
复制
insert into t(id,k) values(id1,k1),(id2,k2);

图片来源:林晓斌《MySQL实战45讲》

Change Buffer的适用场景在于:写多读少的场景,数据页在写完以后不会被马上访问到。

Change Buffer不适用的场景:写少读多的场景,数据页写完后立马会被查询到,会立即出发merge操作,因此随机IO访问的次数不会减少。

Change Buffer与Redo log的对比:Redo log主要节省的是随机写磁盘的IO消耗(转为顺序写),而Change Buffer主要节省的是随机读磁盘的IO消耗

2 为何MySQL有时候会选错索引?

MySQL中,在索引建立之后,一条语句可能会命中多个索引,这时,索引的选择就会交由 优化器来选择合适的索引。优化器选择索引的目的,是找到一个最优的执行方案,并用最小的代价去执行语句。

不过,MySQL中有时候会选错索引,导致查询性能较差,主要会出现在以下场景中。

场景1:由于索引统计信息不准确导致

解决办法:使用 analyze table 命令重新统计索引信息。

原因:MySQL 在真正开始执行语句之前,并不能精确地知道满足这个条件的记录有多少条,而只能根据统计信息来估算记录数。索引统计(cardinality列)信息不够准确,会导致MySQL优化器无法准确判断选择。

补充:MySQL优化器对于索引的选择,基于索引基数(cardinality)与表中数据行数(n_row_in_table)的比值,即索引选择性:

代码语言:javascript
复制
索引选择性=索引基数/数据行

cardinality非常关键,表示索引中不重复记录的预估值。需要注意的是cardinality是一个预估值,而不是一个准确值。基本上用户也不可能得到一个准确的值。在实际应用中,这个基数越大,索引的区分度越好。

我们可以使用 show index 方法,看到一个索引的基数。

场景2:优化器误判导致

解决办法A:应用端使用 force index 强行选择一个索引。

代码语言:javascript
复制
select * from t force index(a) where a between 10000 and 20000;

解决办法B:修改语句引导MySQL使用期望的索引。此方法不具备通用性。

解决办法C:新增更合适的索引 或 删除误用的索引。此方法是一个绕过问题的思路。

3 如何给字符串字段加索引?

简单粗暴:直接创建完整索引

直接创建完整索引,可能比较占用空间

图片来源:林晓斌《MySQL实战45讲》

前缀索引:节省空间的方式

创建前缀索引,比较节省空间,但会增加查询扫描次数,并且不能使用覆盖索引。比如下图就展示了一个截取了email前六位的前缀索引。

图片来源:林晓斌《MySQL实战45讲》

此方式需要判断出前缀的合适长度,根据业务来定,主要看区分度。

示例:

代码语言:javascript
复制
select count(distinct left(email,4))as L4, 
count(distinct left(email,5))as L5, 
count(distinct left(email,6))as L6 
from SUser;

倒序存储

倒序存储,再创建前缀索引,用于绕过字符串本身前缀的区分度不够的问题。

此方式适用于前缀区分度不高但后缀区分度高的场景,目的是提高索引的区分度。但此方式不支持范围扫描。

示例:

代码语言:javascript
复制
select field_list from t 
where id_card = reverse('input_id_card_string');

Hash字段索引

创建hash字段索引,查询性能稳定,但有额外的存储和计算消耗。

此方式不支持范围扫描。

示例:

代码语言:javascript
复制
select field_list from t 
where id_card_crc=crc32('input_id_card_string') 
and id_card='input_id_card_string';

4 小结

本文总结了MySQL的索引相关的实践使用问题,包括普通索引和唯一索引如何选择,MySQL为什么有时候会选错索引,怎么给字符串字段加索引。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-03-01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 普通索引与唯一索引如何选择?
    • 先说结论
      • 关于Change Buffer机制
      • 2 为何MySQL有时候会选错索引?
        • 场景1:由于索引统计信息不准确导致
          • 场景2:优化器误判导致
          • 3 如何给字符串字段加索引?
            • 简单粗暴:直接创建完整索引
              • 前缀索引:节省空间的方式
                • 倒序存储
                  • Hash字段索引
                  • 4 小结
                  相关产品与服务
                  云数据库 SQL Server
                  腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档