7.4.4 【MySQL】索引字符串值的前缀

我们知道一个字符串其实是由若干个字符组成,如果我们在 MySQL 中使用 utf8 字符集去存储字符串的话,编码一个字符需要占用 1~3 个字节。假设我们的字符串很长,那存储一个字符串就需要占用很大的存储空间。在我们需要为这个字符串列建立索引时,那就意味着在对应的 B+ 树中有这么两个问题:

  • B+ 树索引中的记录需要把该列的完整字符串存储起来,而且字符串越长,在索引中占用的存储空间越大。
  • 如果 B+ 树索引中索引列存储的字符串很长,那在做字符串比较时会占用更多的时间。

我们前边儿说过索引列的字符串前缀其实也是排好序的,所以索引的设计者提出了个方案 --- 只对字符串的前几个字符进行索引也就是说在二级索引的记录中只保留字符串前几个字符。这样在查找记录时虽然不能精确的定位到记录的位置,但是能定位到相应前缀所在的位置,然后根据前缀相同的记录的主键值回表查询完整的字符串值,再对比就好了。这样只在 B+ 树中存储字符串的前几个字符的编码,既节约空间,又减少了字符串的比较时间,还大概能解决排序的问题,何乐而不为,比方说我们在建表语句中只对 name 列的前10个字符进行索引可以这么写:

CREATE TABLE person_info( 
name VARCHAR(100) NOT NULL, 
birthday DATE NOT NULL,phone_number CHAR(11) NOT NULL, country varchar(100) NOT NULL, KEY idx_name_birthday_phone_number (name(10), birthday, phone_number)); 

name(10) 就表示在建立的 B+ 树索引中只保留记录的前 10 个字符的编码,这种只索引字符串值的前缀的策略是我们非常鼓励的,尤其是在字符串类型能存储的字符比较多的时候。

7.4.4.1 索引列前缀对排序的影响

如果使用了索引列前缀,比方说前边只把 name 列的前10个字符放到了二级索引中,下边这个查询可能就有点儿尴尬了:

SELECT * FROM person_info ORDER BY name LIMIT 10;

因为二级索引中不包含完整的 name 列信息,所以无法对前十个字符相同,后边的字符不同的记录进行排序,也就是使用索引列前缀的方式无法支持使用索引排序,只好乖乖的用文件排序。

7.4.5 让索引列在比较表达式中单独出现

假设表中有一个整数列 my_col ,我们为这个列建立了索引。下边的两个 WHERE 子句虽然语义是一致的,但是在效率上却有差别:

1. WHERE my_col *

2 < 42. WHERE my_col < 4/2

第1个 WHERE 子句中 my_col 列并不是以单独列的形式出现的,而是以 my_col * 2 这样的表达式的形式出现的,存储引擎会依次遍历所有的记录,计算这个表达式的值是不是小于 4 ,所以这种情况下是使用不到为 my_col 列建立的 B+ 树索引的。而第2个 WHERE 子句中 my_col 列并是以单独列的形式出现的,这样的情况可以直接使用B+ 树索引。

所以结论就是:如果索引列在比较表达式中不是以单独列的形式出现,而是以某个表达式,或者函数调用形式出现的话,是用不到索引的。

7.4.6 主键插入顺序

我们知道,对于一个使用 InnoDB 存储引擎的表来说,在我们没有显式的创建索引时,表中的数据实际上都是存储在 聚簇索引 的叶子节点的。而记录又是存储在数据页中的,数据页和记录又是按照记录主键值从小到大的顺序进行排序,所以如果我们插入的记录的主键值是依次增大的话,那我们每插满一个数据页就换到下一个数据页继续插,而如果我们插入的主键值忽大忽小的话,这就比较麻烦了,假设某个数据页存储的记录已经满了,它存储的主键值在 1~100 之间:

如果此时再插入一条主键值为 9 的记录,那它插入的位置就如下图:

可这个数据页已经满了啊,再插进来咋办呢?我们需要把当前页面分裂成两个页面,把本页中的一些记录移动到新创建的这个页中。页面分裂和记录移位意味着什么?意味着:性能损耗!所以如果我们想尽量避免这样无谓的性能损耗,最好让插入的记录的主键值依次递增,这样就不会发生这样的性能损耗了。所以我们建议:让主键具有 AUTO_INCREMENT ,让存储引擎自己为表生成主键,而不是我们手动插入 ,比方说我们可以这样定义person_info 表:

CREATE TABLE person_info( 
id INT UNSIGNED NOT NULL AUTO_INCREMENT, 
name VARCHAR(100) NOT NULL, 
birthday DATE NOT NULL, 
phone_number CHAR(11) NOT NULL, 
country varchar(100) NOT NULL, 
PRIMARY KEY (id), 
KEY idx_name_birthday_phone_number (name(10), birthday, phone_number)); 

我们自定义的主键列 id 拥有 AUTO_INCREMENT 属性,在插入记录时存储引擎会自动为我们填入自增的主键值。

7.4.7 冗余和重复索引

有时候有的同学有意或者无意的就对同一个列创建了多个索引,比方说这样写建表语句:

CREATE TABLE person_info( 
id INT UNSIGNED NOT NULL AUTO_INCREMENT, 
name VARCHAR(100) NOT NULL, 
birthday DATE NOT NULL, 
phone_number CHAR(11) NOT NULL, 
country varchar(100) NOT NULL, 
PRIMARY KEY (id), 
KEY idx_name_birthday_phone_number (name(10), birthday, phone_number), 
KEY idx_name (name(10))); 

我们知道,通过 idx_name_birthday_phone_number 索引就可以对 name 列进行快速搜索,再创建一个专门针对name 列的索引就算是一个 冗余 索引,维护这个索引只会增加维护的成本,并不会对搜索有什么好处。

另一种情况,我们可能会对某个列重复建立索引,比方说这样:

CREATE TABLE repeat_index_demo ( 
c1 INT PRIMARY KEY, 
c2 INT, 
UNIQUE uidx_c1 (c1), 
INDEX idx_c1 (c1)); 

我们看到, c1 既是主键、又给它定义为一个唯一索引,还给它定义了一个普通索引,可是主键本身就会生成聚簇索引,所以定义的唯一索引和普通索引是重复的,这种情况要避免。

7.5 总结

  1. B+ 树索引在空间和时间上都有代价,所以没事儿别瞎建索引。
  2. B+ 树索引适用于下边这些情况:
  • 全值匹配
  • 匹配左边的列
  • 匹配范围值
  • 精确匹配某一列并范围匹配另外一列
  • 用于排序
  • 用于分组
  1. 在使用索引时需要注意下边这些事项:
  • 只为用于搜索、排序或分组的列创建索引
  • 为列的基数大的列创建索引
  • 索引列的类型尽量小
  • 可以只对字符串值的前缀建立索引
  • 只有索引列在比较表达式中单独出现才可以适用索引
  • 为了尽可能少的让 聚簇索引 发生页面分裂和记录移位的情况,建议让主键拥有 AUTO_INCREMENT 属性。
  • 定位并删除表中的重复和冗余索引
  • 尽量使用 覆盖索引 进行查询,避免 回表 带来的性能损耗。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/82748.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一键集成prometheus监控微服务接口平均响应时长

一、效果展示 二、环境准备 prometheus + grafana环境 参考博文:https://blog.csdn.net/luckywuxn/article/details/129475991 三、导入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter

UE5学习笔记(1)——从源码开始编译安装UE5

目录 0. 前期准备1. Git bash here2. 克隆官方源码。3. 选择安装分支4. 运行Setup.bat&#xff0c;下载依赖文件5. 运行GenerateProjectFiles.bat生成工程文件6. 生成完成&#xff0c;找到UE5.sln/UE4.sln7. 大功告成 0. 前期准备 0.1 在windows的话&#xff0c;建议装一个Git…

Markdown(MD)——Typora Markdown安装教程(2023九月亲测可用!!!)

目录 一、简介 1.Markdown简介 2.Markdown特点 3.Typora简介 二、安装教程 1.下载安装包 2.解压到文件夹 3.安装 4.破解 ​编辑5.激活 三、Markdown常用语法 1.常用语法 2.用于编辑LaTex公式 四、其他编辑器 一、简介 1.Markdown简介 Markdown 是一种轻量级标记语…

WPF——Control与Template理解

文章目录 一、前言二、控件三、模板3.1 DataTemplate3.2 ControlTemplate3.3 ContentPresenter 四、结语 一、前言 最近又翻看了下刘铁猛的《深入浅出WPF》&#xff0c;发现对模板章节中的部分内容有了更深的体会&#xff0c;所以写篇文扯扯。 文章标题是Control与Template&a…

企业级数据仓库-理论知识

D3 AM 大数据中间件 Hive&#xff1a;将SQL转化成分布式Map/Reduce进行运算&#xff0c;也支持转换成Spark,需要单独安装Hive集群才能访问Spark,支持60%的SQL&#xff0c;延迟比较大。SparkSQL:属于Spark生态圈&#xff0c;Hive on Sqark。HBase: NoSQL,高并发读&#xff0c;适…

c语言进阶部分详解(指针进阶1)

大家好&#xff01;指针的初阶内容我已经写好&#xff0c;可移步至我的文章&#xff1a;c语言进阶部分详解&#xff08;指针初阶&#xff09;_总之就是非常唔姆的博客-CSDN博客 基本内容我便不再赘述&#xff0c;直接带大家进入进阶内容&#xff1a; 目录 一.字符指针 1.讲解…

Mac 安装软件各种报错解决方案

Mac 安装软件各种报错解决方案 文章目录 Mac 安装软件各种报错解决方案一. 打开允许“允许任何来源”二. 无法打开"xxx"&#xff0c;因为它不是从App Store下载三. 无法打开"xxx"&#xff0c;因为 Apple无法检查其是否包含恶意软件。四. "xxx"已…

【入门篇】ClickHouse最优秀的开源列式存储数据库

文章目录 一、什么是ClickHouse&#xff1f;OLAP场景的关键特征列式数据库更适合OLAP场景的原因输入/输出CPU 1.1 ClickHouse的定义与发展历程1.2 ClickHouse的版本介绍 二、ClickHouse的主要特性2.1 高性能的列式存储2.2 实时的分析查询2.3 高度可扩展性2.4 数据压缩2.5 SQL支…

C语言——通讯录管理系统

通讯录管理系统项目简介 功能说明 控制台黑窗口实现程序需要满足以下几个功能 程序开始运行时首先显示选择菜单界面&#xff0c;根据用户输入确定实现何种功能 程序界面 代码实现 多文件实现 和之前写的实战项目类似&#xff0c;这里同样采用多文件实现的方式 多文件写代码…

各种电机驱动原理

步进电机 步进电机参考资料 野火官方文档 步进电机驱动原理 上面参考文档中有的内容就不写了&#xff0c;写一下我自己的总结吧。 说明&#xff1a; 电机驱动器输入信号有电机转动方向信号DIR&#xff0c;电机转速信号PWM&#xff0c;电机使能信号EN&#xff1b;电机驱动器…

S7-1200PLC和LED电子看板通信(TCP/IP)

S7-200SMART PLC和LED电子看板通信应用,请查看下面文章链接: SMART 200 PLC UDP通讯应用LED看板_RXXW_Dor的博客-CSDN博客开放式用户通信 (OUC) 库:数据解析:https://rxxw-control.blog.csdn.net/article/details/121424897这篇博客我们主要介绍S7-1200PLC和LED电子看板通…

servlet 引用src目录下子目录的class文件方法

1、MyServlet class文件所处的目录结构如下&#xff1a; 2、如果在url里直接引用是不行的&#xff0c;http://localhost:9092/GetRequest_Web_exploded/MyServlet 3、需要在web.xml映射后才行&#xff1a; MyServlet com.example.MyServlet <servlet-mapping><ser…

HI_NAS linux 记录

dev/root 100% 占用解决记录 通过下面的命令查看各文件夹 大小 sudo du --max-depth1 -h # 统计当前文件夹下各个文件夹的大小显示为M 最终发现Var/log 占用很大空间 发现下面两个 log 占用空间很大&#xff0c;直接 rm-rf 即可 HI NAS python3 记录 # 安装pip3 sudo apt u…

Linux下C语言使用 netlink sockets与内核模块通信

netlink简介 Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最常用的接口。在Linux标准内核中&#xff0c;系统默认集成了很多netlink实例&#xff0c;比如日志上报、路由系统等&#xff0c;netlink消息是双向的&a…

【golang】调度系列之P

调度系列 调度系列之goroutine 调度系列之m 在前面两篇中&#xff0c;分别介绍了G和M&#xff0c;当然介绍的不够全面&#xff08;在写后面的文章时我也在不断地完善前面的文章&#xff0c;后面可能也会有更加汇总的文章来统筹介绍GMP&#xff09;。但是&#xff0c;抛开技术细…

移动端APP测试-如何指定测试策略、测试标准?

制定项目的测试策略是一个重要的步骤&#xff0c;可以帮助测试团队明确测试目标、测试范围、测试方法、测试资源、测试风险等&#xff0c;从而提高测试效率和质量。本篇是一些经验总结&#xff0c;理论分享。并不是绝对正确的&#xff0c;也欢迎大家一起讨论。 文章目录 一、测…

使用Linkerd实现流量管理:学习如何使用Linkerd的路由规则来实现流量的动态控制

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Mac 错误zsh: command not found: brew解决方法

打开iterm或其他shell终端&#xff0c;执行命令&#xff1a; /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 选择下载brew的源&#xff0c;输入1~6任意都行 根据提示输入Y及开机密码 最后执行&#xff1a;source ~/.z…

什么是鉴权?一篇文章带你了解postman的多种方式

一、什么是鉴权&#xff1f; 鉴权也就是身份认证&#xff0c;就是验证您是否有权限从服务器访问或操作相关数据。发送请求时&#xff0c;通常必须包含相应的检验参数以确保请求具有访问权限并返回所需数据。通俗的讲就是一个门禁&#xff0c;您想要进入室内&#xff0c;必须通过…

一个Qt鼠标透传场景与事件过滤器的用法

一个Qt鼠标透传场景与事件过滤器的用法 最近工作中遇到一个开发场景&#xff0c;将一个QWidget控件&#xff08;称为控件A&#xff09;放入QScrollArea&#xff0c;该控件A重写了QWidget::wheelEvent&#xff0c;根据鼠标滚轮事件缩放内部的绘制视图。当控件过大时&#xff0c…