MySQL核心知识学习之路(5)
作为一个后端工程师,想必没有人没用过数据库,跟我一起复习一下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(不在内存中,需要写入到磁盘)。
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)的比值,即索引选择性:
索引选择性=索引基数/数据行
cardinality非常关键,表示索引中不重复记录的预估值。需要注意的是cardinality是一个预估值,而不是一个准确值。基本上用户也不可能得到一个准确的值。在实际应用中,这个基数越大,索引的区分度越好。
我们可以使用 show index 方法,看到一个索引的基数。

场景2:优化器误判导致
解决办法A:应用端使用 force index 强行选择一个索引。
select * from t force index(a) where a between 10000 and 20000;
解决办法B:修改语句引导MySQL使用期望的索引。此方法不具备通用性。
解决办法C:新增更合适的索引 或 删除误用的索引。此方法是一个绕过问题的思路。
3 如何给字符串字段加索引?
简单粗暴:直接创建完整索引
直接创建完整索引,可能比较占用空间

图片来源:林晓斌《MySQL实战45讲》
前缀索引:节省空间的方式
创建前缀索引,比较节省空间,但会增加查询扫描次数,并且不能使用覆盖索引。比如下图就展示了一个截取了email前六位的前缀索引。

图片来源:林晓斌《MySQL实战45讲》
此方式需要判断出前缀的合适长度,根据业务来定,主要看区分度。
示例:
select count(distinct left(email,4))as L4,
count(distinct left(email,5))as L5,
count(distinct left(email,6))as L6
from SUser;
倒序存储
倒序存储,再创建前缀索引,用于绕过字符串本身前缀的区分度不够的问题。
此方式适用于前缀区分度不高但后缀区分度高的场景,目的是提高索引的区分度。但此方式不支持范围扫描。
示例:
select field_list from t
where id_card = reverse('input_id_card_string');
Hash字段索引
创建hash字段索引,查询性能稳定,但有额外的存储和计算消耗。
此方式不支持范围扫描。
示例:
select field_list from t
where id_card_crc=crc32('input_id_card_string')
and id_card='input_id_card_string';
4 小结
本文总结了MySQL的索引相关的实践使用问题,包括普通索引和唯一索引如何选择,MySQL为什么有时候会选错索引,怎么给字符串字段加索引。
参考资料
林晓斌(丁奇),《MySQL实战45讲》
扫码订阅《MySQL实战45讲》


MySQL核心知识学习之路(5)的更多相关文章
- 零基础的学习者应该怎么开始学习呢?Python核心知识学习思维分享
近几年,Python一路高歌猛进,成为最受欢迎的编程语言之一,受到无数编程工作者的青睐. 据悉,Python已经入驻部分小学生教材,可以预见学习Python将成为一项提高自身职业竞争力的必修课.那么零 ...
- MySQL索引知识学习笔记
目录 一.索引的概念 二.索引分类 三.索引用法 四 .索引架构简介 五.索引适用的情况 六.索引不适用的情况 继我的上篇博客:Oracle索引知识学习笔记,再记录一篇MySQL的索引知识学习笔记,本 ...
- MYSQL+PHP的学习之路
MYSQL+PHP 先从MYSQL开始吧 第一步:SQL语句基础 1.书籍 2.网站: 这个网站在线测试和考试http://sqlzoo.net/wiki/SELECT_basics/zh 3.学习过 ...
- mysql 核心知识要点
整体知识介绍:mysql基本操作和使用,mysql优化(索引,分表等),mysql部署(读写分离,负载均衡等) 数据库基本介绍:数据库概念,常用数据库,web应用三大软件分工,PHP动态语言特点(处理 ...
- MySQL核心知识
MySQL常用的命令 启动:net start mySql; 进入:mysql -u root -p/mysql -h localhost -u root -p databaseName; 列出数据库 ...
- Webwork 学习之路【03】核心类 ServletDispatcher 的初始化
1. Webwork 与 Xwork 搭建环境需要的的jar 为:webwork-core-1.0.jar,xwork-1.0.jar,搭建webwork 需要xwork 的jar呢?原因是这样的,W ...
- MySQL学习之路(一)——初涉MySQL。
MySQL学习之路(一) 1.1MySQL的概述 MySQL由瑞典MySQL AB公司开发,目前属于Oracle公司. MySQL是一个开源的关系型数据库管理系统. MySQL分为社区版和企业版. 1 ...
- Docker 与 K8S学习笔记(二)—— 容器核心知识梳理
本篇主要对容器相关核心知识进行梳理,通过本篇的学习,我们可以对容器相关的概念有一个全面的了解,这样有利于后面的学习. 一.什么是容器? 容器是一种轻量级.可移植.自包含的软件打包技术,使应用程序可以在 ...
- 阿里封神谈hadoop学习之路
阿里封神谈hadoop学习之路 封神 2016-04-14 16:03:51 浏览3283 评论3 发表于: 阿里云E-MapReduce >> 开源大数据周刊 hadoop 学生 s ...
- 13本热门书籍免费送!(Python、SpingBoot、Entity Framework、Ionic、MySQL、深度学习、小程序开发等)
七月第一周,网易云社区联合清华大学出版社为大家送出13本数据分析以及移动开发的书籍(Python.SpingBoot.Entity Framework.Ionic.MySQL.深度学习.小程序开发等) ...
随机推荐
- Vue3封装支持Base64导出的电子签名组件
效果图 准备工作 组件内用到elementPlus,vue-esign组件,使用前提前安装好. 组件代码 <template> <!-- 签名容器 --> <div cl ...
- Sublime Text 3汉化教程
一.初始化插件仓库 ctrl+`(esc键下方那一个)打开控制台输入以下代码回车 import urllib.request,os,hashlib; h = '6f4c264a24d933ce70df ...
- harmonyOS基础- 快速弄懂HarmonyOS ArkTs基础组件、布局容器(前端视角篇)
大家好!我是黑臂麒麟,一位6年的前端: if you're change the world, you're workingon important things. you're excited to ...
- C#/.NET/.NET Core优秀项目和框架2025年3月简报
前言 公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的详细介绍.功能特点.使用方式以及部分功能 ...
- 🎀Docker下Dubbo服务优雅上下线实现
简介 在Docker容器环境中部署基于Dubbo的服务时,实现服务的优雅上下线是至关重要的.这通常涉及到两个关键步骤:首先,确保服务能够从注册中心摘除,停止接受新的请求:其次,等待所有正在处理的请求完 ...
- 一文速通Python并行计算:08 Python多进程编程-multiprocessing模块、进程的创建命名、获取进程ID、创建守护进程和进程的终止
一文速通 Python 并行计算:08 Python 多进程编程-multiprocessing 模块.进程的创建命名.获取进程 ID.创建守护进程和进程的终止 摘要: 本节介绍 Python 中 m ...
- ThinkPHP 中闭包在数组查询条件中的深度应用
一.闭包与数组条件的协同原理 在 ThinkPHP 的查询体系中,数组条件是构建查询逻辑的核心载体.当数组条件的值为闭包(Closure)时,框架会自动将其解析为动态子查询生成器,实现运行时按需构建 ...
- Spring基于注解的AOP事务控制
Spring基于注解的AOP事务控制 源码 代码测试 pom.xml <?xml version="1.0" encoding="UTF-8"?> ...
- json格式转为List集合
一.JSON格式 {"code":"200","msg":"success","data":[&qu ...
- 制作带sshd功能的centos镜像
docker run -it --name node1 docker.io/centos bash 创建node1容器 docker exec -it node1 bash 进入node1 yum ...