MySQL 索引介绍和最佳实践_索引有什么最佳实践-程序员宅基地

技术标签: mysql  数据库  

一、前言

索引是帮助高效获取数据排好序的数据结构,这里都会以MySQL InnoDB 存储引擎做讲解。

  • InnoDB 存储引擎索引有两个特点
    • 聚簇索引
      索引与数据存放在一起、一张表只有一个聚簇索引找到索引的同时也找到了数据,同时聚簇索引具有唯一性,默认是主键,如果表中没有定义主键,InnoDB 会选择一个非空唯一索引代替。如果没有,InnoDB 会定义一个隐藏的_rowid 列来作为聚簇索引。
    • 非聚簇索引
      索引与数据分开存放,索引结构的叶子节点指向了数据的对应行,如:一个表id字段是主键索引,创建一个name字段的普通索引,叶子节点是指向对应主键索引的值,通过name字段的普通索引找到对应id值,然后通过id回表主键索引获取到行数据。

二、索引类型

1.1 主键索引(PRIMARY KEY)

主键索引非空且唯一,在 InnoDB 存储引擎中会作为聚簇索引叶子节点会存放所有行数据。

ALTER TABLE `table_name` ADD PRIMARY KEY (`column`);

1.2 唯一索引(UNIQUE)

唯一索引值唯一,可为NULL值,而且可以多行数据为NULL值,也可以使用多个列作为唯一索引,在存储索引时会对多列组合唯一判断。

ALTER TABLE `table_name` ADD UNIQUE INDEX `index_name`(`column`) USING BTREE;

1.3 普通索引(NORMAL)

普通索引是我们最常用的一类索引,可以使用单个列作为索引,也可以使用多个列作为索引,多列索引也叫做复合索引或者组合索引,在字段的长度超过索引限制(索引最大长度是768字节),可以为字段的部分前缀创建索引。

1.3.1 单列普通索引
ALTER TABLE `table_name` ADD INDEX `index_name`(`column`);
1.3.2 单列前缀普通索引
ALTER TABLE `table_name` ADD INDEX `index_name`(`column`(2));
1.3.3 多列普通索引
ALTER TABLE `table_name` ADD INDEX `index_name`(`column1`, `column2`);
1.3.4 多列前缀普通索引
ALTER TABLE `table_name` ADD INDEX `index_name`(`column1`(2), `column2`(3));
1.3.5 升序降序索引
# 默认升序
ALTER TABLE `table_name` ADD INDEX `index_name`(`column1`, `column2` ASC, `column3` DESC);

1.4 空间索引(SPATIAL)

空间索引是对空间数据类型的字段建立的索引,MYSQL使用SPATIAL关键字进行扩展,使其能够在空间数据类型的语法上创建空间索引。

# 建表
CREATE TABLE `gis_position` (
	`id` INT NOT NULL,
	`gis` geometry NOT NULL COMMENT '空间位置信息',
	`geohash` VARCHAR ( 20 ) GENERATED ALWAYS AS (st_geohash ( `gis`, 12 )) VIRTUAL,
	PRIMARY KEY ( `id` ) 
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4 COMMENT = '空间位置信息';

# 创建空间索引
ALTER TABLE gis_position ADD SPATIAL INDEX `idx_gis` ( `gis` );

1.5 全文索引(FULLTEXT)

全文索引类似于 elasticsearch 这样的搜索引擎,会对索引内容进行分词,当然比起 elasticsearch 还是差一些。

ALTER TABLE `table_name` ADD FULLTEXT INDEX `index_name`(`column`);

三、表数据准备(后续演示都基于这个表)

我这里库使用的字符集为utf8mb4,一个字符占用4个字节,utf8占用3个字节,如果字段为varchar类型,需要加的2字节用来存储字符串长度,因为varchar是变长字符串。

CREATE TABLE `company_staff` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) NOT NULL DEFAULT '' COMMENT '姓名',
  `age` int(11) NOT NULL DEFAULT '0' COMMENT '年龄',
  `position` varchar(20) NOT NULL DEFAULT '' COMMENT '职位',
  `interest` varchar(20) DEFAULT NULL COMMENT '兴趣爱好',
  `entry_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入职时间',
  PRIMARY KEY (`id`),
  KEY `idx_name_age_position` (`name`,`age`,`position`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_as_cs COMMENT='公司员工表';

INSERT INTO company_staff(name,age,position,interest,entry_time) VALUES('Kerwin',28,'cto','唱跳',NOW());
INSERT INTO company_staff(name,age,position,interest,entry_time) VALUES('Alia',26,'dev','rap',NOW());
INSERT INTO company_staff(name,age,position,interest,entry_time) VALUES('Coco',26,'dev','篮球',NOW());

四、索引最佳实践

对MYSQL的 explain SQL分析工具不熟的可以看看 MySQL explain SQL分析工具详解与最佳实践

4.1 全值匹配

  • 通过 name 字段精准匹配
EXPLAIN SELECT * FROM company_staff WHERE name= 'Kerwin';

在这里插入图片描述
这里可以看到使用了组合索引idx_name_age_position,我们的name字段为varchar(30),计算出name字段占用字节数为key_len = 30*4+2=122,和我们的执行计划中的key_len相等,同时ref为const,可以确定通过name字段精准匹配,使用到了组合索引idx_name_age_position,但是只使用到了一个name字段。

  • 通过 name + age 字段精准匹配
EXPLAIN SELECT * FROM company_staff WHERE name= 'Kerwin' AND age=28;

在这里插入图片描述
和上面通过name字段匹配执行计划类似,name字段占用字节数为122,age字段为int类型,int类型占用4个字节,name + age 字段一共为126字节和执行计划的key_len相等,同时ref为const,const代表使用了两个字段常量,可以确定使用到了组合索引idx_name_age_position,并且使用到了两个字段name + age。

  • 通过 name + age + position 字段精准匹配
EXPLAIN SELECT * FROM company_staff WHERE name= 'Kerwin' AND age=28 AND position='cto';

在这里插入图片描述
position字段为varchar(20),计算出字节数为20*4+2=82,在加上 name、age占用的字节数合计122+4+82=208字节和执行计划的key_len相等,同时ref为const,const,const代表使用了三个字段常量,确认idx_name_age_position索引中三个字段全部被使用到了。

4.2 最左前缀原则

如果索引了多列,要遵守最左前缀原则,指的是查询从索引的最左前列开始并且不跳过索引中的列。

PS:在MySQL8.0的时候加入了一个跳跃索引,在某些情况下会跳过中间没有被匹配的列去匹配后面的列,如果使用到了跳跃索引那么在Extra中会出现 Index skip scan。

  • 通过 age 字段精准匹配
EXPLAIN SELECT * FROM company_staff WHERE age= 28;

在这里插入图片描述
我们直接使用age查询,这里发现没有使用到索引,因为我们的组合索引第一个值是name,如果查询条件中没有name值是无法使用索引的。

  • 通过 name + position 字段精准匹配
EXPLAIN SELECT * FROM company_staff WHERE name= 'Kerwin' AND position='cto';

在这里插入图片描述
我们这里使用name + position 字段精准匹配,执行计划中显示使用到了索引,但是key_len=122,name字段占用的字节数刚好是122,证明这里虽然使用到了idx_name_age_position索引,但是只使用到了name一个字段匹配。

4.3 在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描

  • 这里将name转化成小写查询
EXPLAIN SELECT * FROM company_staff WHERE LOWER(name)= 'kerwin';

在这里插入图片描述

4.4 不能使用索引中范围查询条件右边的列

  • 通过name + position 精准匹配和age范围查询
EXPLAIN SELECT * FROM company_staff WHERE name= 'Kerwin' AND age<35 AND position='cto';

在这里插入图片描述
我们查询时age条件使用范围查询,这里可以看到key_len=126,name+age字节数为126,没有使用到position

4.5 尽量使用覆盖索引

查询条件和响应结果的列都存在索引中,这样只需要通过索引就能获取需要的数据,就不会在进行回表。

EXPLAIN SELECT name,age,position FROM company_staff WHERE name= 'Kerwin' AND age=28 AND position='cto';

在这里插入图片描述

4.6 MySQL8.0之前在使用不等于(!=或者<>),not in ,not exists 的时候无法使用索引会导致全表扫描

in、< 小于、 > 大于、 <=、>= 这些,MySQL内部优化器会根据检索比例、表大小等多个因素整体评估是否使用索引,MySQL8.0的时候不等于(!=或者<>),not in 也会根据检索比例、表大小等多个因素整体评估是否使用索引。

EXPLAIN SELECT * FROM company_staff WHERE name != 'Kerwin';

在这里插入图片描述

4.7 is null,is not null 一般情况下也无法使用索引

EXPLAIN SELECT * FROM company_staff WHERE name IS NULL;

在这里插入图片描述

4.8 like以通配符开头(‘%abc…’)索引失效会变成全表扫描操作

like查询是可以走索引的,但是只能通过前缀查询,不能以通配符开头。

  • 模糊匹配 name 字段,以win结尾的数据
EXPLAIN SELECT * FROM company_staff WHERE name LIKE "%win";

在这里插入图片描述

  • 模糊匹配 name 字段,以Ker开头的数据
EXPLAIN SELECT * FROM company_staff WHERE name LIKE "Ker%";

在这里插入图片描述

4.9 字符串不加单引号索引失效

字符串字段查询如果不加单引号或者算引号会发生隐式转换导致索引失效,如果是数字类型字段查询时使用单引号索引不会失效。

EXPLAIN SELECT * FROM company_staff WHERE name = 666;

在这里插入图片描述
发生隐式转换后SQL相当于变成SELECT * FROM company_staff WHERE CAST(name AS signed int) = 666;,name字段使用了函数索引失效

4.10 少用or或in,用它查询时,MySQL不一定使用索引

MySQL内部优化器会根据检索比例、表大小等多个因素整体评估是否使用索引,拿我这里的数据来说,表里一共三条数据,我IN查询4个值以内(包含4个值)是可以走索引的,一旦超过4个值到了5个值索引就会失效了,MySQL内部优化器会认为我们要IN查询这5个值全表扫描耗时会比使用索引要快,因为使用非聚簇索引是需要回表的。

EXPLAIN SELECT * FROM company_staff WHERE name IN ('4Kerwin','3Kerwin','2Kerwin','1Kerwin','Kerwin');

在这里插入图片描述

4.11 范围查询索引失效

MySQL内部优化器会根据检索比例、表大小等多个因素整体评估是否使用索引,可能是由于单次数据量查询过大导致优化器最终选择不走索引。

要想看到效果需要先添加10000条数据的样子,如果只有几条数据是会一直走索引。

  • 使用存储过程插入10000条数据
## 创建一个插入数据的存储过程
DROP PROCEDURE IF EXISTS insert_company_staff;
delimiter;;
CREATE PROCEDURE insert_company_staff () 
BEGIN
	DECLARE i INT;
	SET i = 1;
	WHILE ( i <= 10000 ) DO
		INSERT INTO `company_staff`(`name`, `age`, `position`, `interest`, `entry_time`) VALUES (CONCAT('Kerwin',i), 28 + i, 'cto', '唱跳', NOW());
		SET i = i + 1;
	END WHILE;
END;;
delimiter;

// 调用存储过程插入数据
CALL insert_company_staff ();
  • 给年龄添加单值索引
ALTER TABLE `company_staff` ADD INDEX `idx_age`(`age`);
  • 范围查询数据
EXPLAIN SELECT * FROM company_staff WHERE age >= 1 AND age <= 3000

在这里插入图片描述
如果查询范围比较大索引可能会失效,缩小查询范围是可以走索引的,最终是否走索引还是MySQL内部优化器会根据检索比例根据表大小等多个因素整体评估。

五、索引使用总结

假设有一个组合索引 index(a,b,c)

where语句 是否使用索引
where a = 3 是:使用到a
where a = 3 and b = 5 是:使用到a,b
where a = 3 and b= 5 and c = 4 是:使用到a,b.c
where b = 3 或 where b = 3 and c = 4 或 where c = 4
where a = 3 and c = 5 是:使用到a,但是c不可以,b中间断了
where a = 3 and b > 4 and c=5 是:使用到a和b,c不能用在范围之后,b断了
where a = 3 and b like "kk%’ and c =4 是:使用到a,b.c
where a = 3 and b like ‘%kk’ and c = 4 是:只用到a
where a = 3 and b like ‘%kk%’ and c =4 是:只用到a
where a = 3 and b like ‘k%kk%’ and c = 4 是:使用到a,b,c

like KK%相当于=常量,%KK和%KK%相当于范围

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_44606481/article/details/133410720

智能推荐

稀疏编码的数学基础与理论分析-程序员宅基地

文章浏览阅读290次,点赞8次,收藏10次。1.背景介绍稀疏编码是一种用于处理稀疏数据的编码技术,其主要应用于信息传输、存储和处理等领域。稀疏数据是指数据中大部分元素为零或近似于零的数据,例如文本、图像、音频、视频等。稀疏编码的核心思想是将稀疏数据表示为非零元素和它们对应的位置信息,从而减少存储空间和计算复杂度。稀疏编码的研究起源于1990年代,随着大数据时代的到来,稀疏编码技术的应用范围和影响力不断扩大。目前,稀疏编码已经成为计算...

EasyGBS国标流媒体服务器GB28181国标方案安装使用文档-程序员宅基地

文章浏览阅读217次。EasyGBS - GB28181 国标方案安装使用文档下载安装包下载,正式使用需商业授权, 功能一致在线演示在线API架构图EasySIPCMSSIP 中心信令服务, 单节点, 自带一个 Redis Server, 随 EasySIPCMS 自启动, 不需要手动运行EasySIPSMSSIP 流媒体服务, 根..._easygbs-windows-2.6.0-23042316使用文档

【Web】记录巅峰极客2023 BabyURL题目复现——Jackson原生链_原生jackson 反序列化链子-程序员宅基地

文章浏览阅读1.2k次,点赞27次,收藏7次。2023巅峰极客 BabyURL之前AliyunCTF Bypassit I这题考查了这样一条链子:其实就是Jackson的原生反序列化利用今天复现的这题也是大同小异,一起来整一下。_原生jackson 反序列化链子

一文搞懂SpringCloud,详解干货,做好笔记_spring cloud-程序员宅基地

文章浏览阅读734次,点赞9次,收藏7次。微服务架构简单的说就是将单体应用进一步拆分,拆分成更小的服务,每个服务都是一个可以独立运行的项目。这么多小服务,如何管理他们?(服务治理 注册中心[服务注册 发现 剔除])这么多小服务,他们之间如何通讯?这么多小服务,客户端怎么访问他们?(网关)这么多小服务,一旦出现问题了,应该如何自处理?(容错)这么多小服务,一旦出现问题了,应该如何排错?(链路追踪)对于上面的问题,是任何一个微服务设计者都不能绕过去的,因此大部分的微服务产品都针对每一个问题提供了相应的组件来解决它们。_spring cloud

Js实现图片点击切换与轮播-程序员宅基地

文章浏览阅读5.9k次,点赞6次,收藏20次。Js实现图片点击切换与轮播图片点击切换<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title></title> <script type="text/ja..._点击图片进行轮播图切换

tensorflow-gpu版本安装教程(过程详细)_tensorflow gpu版本安装-程序员宅基地

文章浏览阅读10w+次,点赞245次,收藏1.5k次。在开始安装前,如果你的电脑装过tensorflow,请先把他们卸载干净,包括依赖的包(tensorflow-estimator、tensorboard、tensorflow、keras-applications、keras-preprocessing),不然后续安装了tensorflow-gpu可能会出现找不到cuda的问题。cuda、cudnn。..._tensorflow gpu版本安装

随便推点

物联网时代 权限滥用漏洞的攻击及防御-程序员宅基地

文章浏览阅读243次。0x00 简介权限滥用漏洞一般归类于逻辑问题,是指服务端功能开放过多或权限限制不严格,导致攻击者可以通过直接或间接调用的方式达到攻击效果。随着物联网时代的到来,这种漏洞已经屡见不鲜,各种漏洞组合利用也是千奇百怪、五花八门,这里总结漏洞是为了更好地应对和预防,如有不妥之处还请业内人士多多指教。0x01 背景2014年4月,在比特币飞涨的时代某网站曾经..._使用物联网漏洞的使用者

Visual Odometry and Depth Calculation--Epipolar Geometry--Direct Method--PnP_normalized plane coordinates-程序员宅基地

文章浏览阅读786次。A. Epipolar geometry and triangulationThe epipolar geometry mainly adopts the feature point method, such as SIFT, SURF and ORB, etc. to obtain the feature points corresponding to two frames of images. As shown in Figure 1, let the first image be ​ and th_normalized plane coordinates

开放信息抽取(OIE)系统(三)-- 第二代开放信息抽取系统(人工规则, rule-based, 先抽取关系)_语义角色增强的关系抽取-程序员宅基地

文章浏览阅读708次,点赞2次,收藏3次。开放信息抽取(OIE)系统(三)-- 第二代开放信息抽取系统(人工规则, rule-based, 先关系再实体)一.第二代开放信息抽取系统背景​ 第一代开放信息抽取系统(Open Information Extraction, OIE, learning-based, 自学习, 先抽取实体)通常抽取大量冗余信息,为了消除这些冗余信息,诞生了第二代开放信息抽取系统。二.第二代开放信息抽取系统历史第二代开放信息抽取系统着眼于解决第一代系统的三大问题: 大量非信息性提取(即省略关键信息的提取)、_语义角色增强的关系抽取

10个顶尖响应式HTML5网页_html欢迎页面-程序员宅基地

文章浏览阅读1.1w次,点赞6次,收藏51次。快速完成网页设计,10个顶尖响应式HTML5网页模板助你一臂之力为了寻找一个优质的网页模板,网页设计师和开发者往往可能会花上大半天的时间。不过幸运的是,现在的网页设计师和开发人员已经开始共享HTML5,Bootstrap和CSS3中的免费网页模板资源。鉴于网站模板的灵活性和强大的功能,现在广大设计师和开发者对html5网站的实际需求日益增长。为了造福大众,Mockplus的小伙伴整理了2018年最..._html欢迎页面

计算机二级 考试科目,2018全国计算机等级考试调整,一、二级都增加了考试科目...-程序员宅基地

文章浏览阅读282次。原标题:2018全国计算机等级考试调整,一、二级都增加了考试科目全国计算机等级考试将于9月15-17日举行。在备考的最后冲刺阶段,小编为大家整理了今年新公布的全国计算机等级考试调整方案,希望对备考的小伙伴有所帮助,快随小编往下看吧!从2018年3月开始,全国计算机等级考试实施2018版考试大纲,并按新体系开考各个考试级别。具体调整内容如下:一、考试级别及科目1.一级新增“网络安全素质教育”科目(代..._计算机二级增报科目什么意思

conan简单使用_apt install conan-程序员宅基地

文章浏览阅读240次。conan简单使用。_apt install conan