mysql 索引使用及优化详情

目录
  • 前言
  • mysql索引原理
  • mysql索引分类
  • 索引创建语法
    • 1、创建索引
    • 2、查看索引
    • 3、删除索引
    • 4、为 username和password创建联合索引
    • 5、给user表添加一个info的字段,并为这个字段添加全文索引
  • 已经存在的表创建、删除索引等
    • 1、使用ALTER TABLE语句创建索引
    • 2、使用ALTER TABLE语句删除索引
  • 常用的索引设计原则
  • 索引失效情况总结
  • 尽量使用覆盖索引

前言

索引对有一定开发经验的同学来说并不陌生,合理使用索引,能大大提升sql查询的性能,可以这么讲,随着业务数据量的不断增长,优化系统的响应速度,很大程度上可以说就是集中在索引的优化上;

mysql索引原理

在正式了解与学习mysql索引之前,先对mysql的索引原理再次回顾下;

我们知道,目前大多数使用的mysql引擎为 innodb,而innodb引擎使用的是 B+ Tree,下面通过几张图快速了解下 B+ Tree的结构,

假如存在下面这张表:

那么通过 B+ Tree构建出来的 “ 以ID为主键索引的树形结构如下:

说明:

  • 叶子节点存放的是ID对应的一条完整的记录;
  • 查找一条记录时,如果是按照ID搜索,则会采用类似二叉树的方式,最终定位到叶子节点的ID对应的那条记录;

也就是说,如果查询的时候,以ID为参数,则效率是最高的,反之,如果以非主键字段,建立索引,则B+Tree的索引结构将会如下,

说明:

  • 主键索引构建出来的 B+Tree 结构保持不变;
  • 再以主键ID之外的字段,构建出一个B+Tree结构,其叶子节点存储的是字段的值以及对应的主键值;

以上关于mysql 的inndb的索引结构原理先介绍到这儿,后文中将会用到里面的东西,还请留意;

mysql索引分类

MySQL的索引包括普通索引、唯一性索引、全文索引、单列索引、多列索引和空间索引等;

  • 从 功能逻辑 上说,索引主要有 4 种,分别是普通索引、唯一索引、主键索引、全文索引;
  • 按照 物理实现方式 ,可以分为 2 种:聚簇索引和非聚簇索引;
  • 按照 作用字段个数 进行划分,分成单列索引和联合索引;、

常规分类

  • 主键索引,针对表的主键创建的索引,默认建表的时候,自动创建,有且只能有一个;
  • 唯一索引,为了避免一个表中的某列数据出现重复的值,可以有多个,关键字:UNIQUE;
  • 常规索引,用于快速定位特定字段的数据,可以有多个;全文索引,
  • 全文索引常用于查找文本中的关键词,而不是比较索引中的值,可以有多个,关键字FULLTEXT;

补充说明

不同的存储引擎支持的索引类型也不一样

  • InnoDB :支持 B-tree、Full-text 等索引,不支持 Hash索引;
  • MyISAM : 支持 B-tree、Full-text 等索引,不支持 Hash 索引;
  • Memory :支持 B-tree、Hash 等索引,不支持 Full-text 索引;
  • NDB :支持 Hash 索引,不支持 B-tree、Full-text 等索引;
  • Archive :不支持 B-tree、Hash、Full-text 等索引;

索引创建语法

数据准备,有如下建表sql

CREATE TABLE `user` (
	`user_id` VARCHAR (32) NOT NULL COMMENT '用户ID',
	`user_name` VARCHAR (64) DEFAULT NULL COMMENT '用户姓名',
	`passwd` VARCHAR (64) NOT NULL COMMENT '密码',
	`email` VARCHAR (64) DEFAULT NULL COMMENT '邮箱',
	`mobile` VARCHAR (32) DEFAULT NULL COMMENT '手机号',
	`address` VARCHAR (128) DEFAULT NULL COMMENT '地址',
	`ID` VARCHAR (18) DEFAULT NULL COMMENT '身份证号',
	`sex` INT (11) DEFAULT NULL COMMENT '用户性别 1:男 2:女',
	PRIMARY KEY (`user_id`)
) ENGINE = INNODB DEFAULT CHARSET = utf8;

1、创建索引

CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX index_name ON table_name (col_name[length],...) [ASC | DESC]
  • UNIQUE 、 FULLTEXT 和 SPATIAL 为可选参数,分别表示唯一索引、全文索引和空间索引;
  • index_name 指定索引的名称,为可选参数,如果不指定,那么MySQL默认col_name为索引名;
  • col_name 为需要创建索引的字段列,该列必须从数据表中定义的多个列中选择;
  • length 为可选参数,表示索引的长度,只有字符串类型的字段才能指定索引长度;
  • ASC 或 DESC 指定升序或者降序的索引值存储;

比如给上表的user_name创建一个唯一索引

CREATE UNIQUE INDEX user_name_idx on `user`(user_name); 

2、查看索引

SHOW INDEX FROM table_name;

3、删除索引

DROP INDEX index_name ON table_name;

删除上面的表创建的唯一索引:

4、为 username和password创建联合索引

create index name_passwd_index on `user`(user_name, passwd);

5、给user表添加一个info的字段,并为这个字段添加全文索引

ALTER  TABLE  `user`  ADD  FULLTEXT ( `info` );

全文索引用match+against方式查询:

SELECT * FROM `user` WHERE MATCH(字段名称) AGAINST (‘查询字符串');

注意点:

使用全文索引前,搞清楚版本支持情况,不同的版本可能对全文索引支持不一样;全文索引比 like + % 快 N 倍,但是可能存在精度问题;如果需要全文索引的是大量数据,建议先添加数据,再创建索引;

已经存在的表创建、删除索引等

现实中,如果之前已经给表创建过相关的索引,现在需要修改或删除,或重新创建,该如何做呢?

1、使用ALTER TABLE语句创建索引

ALTER TABLE table_name ADD [UNIQUE | FULLTEXT | SPATIAL] [INDEX | KEY] [index_name] (col_name[length],…) [ASC | DESC]

比如给 user表的mobile字段添加索引

ALTER TABLE `user` ADD INDEX `idx_mobile` (`mobile`);

2、使用ALTER TABLE语句删除索引

ALTER TABLE table_name DROP INDEX index_name;

或者直接使用drop语句

DROP INDEX index_name ON table_name;

说明

删除表中的列时,如果要删除的列为索引的组成部分,则该列也会从索引中删除。如果组成索引的所有列都被删除,则整个索引将被删除;

常用的索引设计原则

在实际开发中,索引并不是越多越好,创建索引需结合业务情况进行综合考量,下面结合实际经验列举出一些常用的索引设计原则,作为创建索引时的参考;

1、字段值在业务中具备唯一性

业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引,比如用户表中,可以通过身份证号或微信号作为 唯一索引

2、频繁作为 WHERE 查询条件的字段

某字段在SELECT语句WHERE 条件中频繁使用,就需要给这个字段创建索引。尤其是数据量大时,创建索引就可以大幅提升查询的效率;比如用户表的 user_id

3、UPDATE、DELETE 的 WHERE 条件列

我们知道,如果更新的这个列创建了索引,在真正执行数据更新的时候,不仅要更新数据,还要更新这个列的索引信息,在这种情况下,建议只对查询的那个字段创建索引(非索引字段更新的时候速度更快);

4、经常 GROUP BY 和 ORDER BY 的列

索引是让数据按某种顺序进行存储或检索,因此使用 GROUP BY 对数据进行分组查询,或者使用 ORDER BY 对数据排序的时候,就需要 对分组或者排序的字段进行索引 。如果待排序的列有多个,那么可以在这些列上建立 组合索引 ,以提升速度;

5、对DISTINCT 字段创建索引

有时候需要使用DISTINCT对某字段进行去重,那么对这个字段创建索引,也会提升查询效率。这是因为索引会对数据按照某种顺序进行排序,所以有了索引在去重的时候会快很多。

6、使用列的类型小的创建索引

7、使用字符串前缀创建索引

举个例子来说,在user表中存在一个邮箱eamil字段,通常来说,对于一个稳定的业务系统,user标准的email格式可以说格式上是固定的,比如 数字@qq.com,名称@163.com等;

我们知道索引也是要占用存储空间的,字段的长度越长,创建的索引最终占用的空间也越大,当表的数据量大到一定程度,查询时就算是检索走索引也会花费较长时间,这时候就可以考虑使用字符串前缀创建索引了;

可以使用下面的语句创建字符串前缀创建索引:

alter table useradd index(email(6));

这里的问题是,截取多少呢?截取多了,达不到节省索引存储空间的目的;截取少了,重复内容太多,字段的散列度(选择性)会降低。怎么计算不同的长度的选择性呢?下面给出一个经验公式作为参考,

先看一下字段在全部数据中的选择度:

select count(distinct email) / count(*) from user;

通过不同长度去计算,与全表的选择性对比:

count(distinct left(列名, 索引长度))/count(*)

8、使用最频繁的列放到联合索引的左侧

这样可以尽可能的向查询时的最佳左前缀原则靠拢;

9、在多字段都要创建索引的情况下,联合索引优于单值索引

试想当user表中,当user_name,mobile都需要创建索引时,分别创建两个单列索引带来的开销,与创建一个联合索引带来的开销哪个更大呢?

10、 区分度高(散列性高)的列适合作为索引

如果表中存在性别这样的字段,就不太适合创建索引,这个需要注意;

11、多表 JOIN 时,创建索引注意事项

  • 连接表数量尽量不要超过 3 张 ,因为每增加一张表就相当于增加了一次嵌套的循环,数量级增长会非常快,严重影响查询的效率;
  • 尽可能对 WHERE 后面的条件字段创建索引 ,因为 WHERE 才是对数据条件的过滤;
  • 对于连接字段创建索引 ,并且该字段在多张表中的类型必须一致 ,字段类型不一致将会带来较大的查询性能损耗;

12、有大量重复数据的列上不要建立索引

在这样的列上一旦创建了索引,比如表中有50万数据,你需要先访问 50 万次索引,然后再访问 50 万次数据表,这样加起来的开销比不使用索引可能还要大;

一个经验值

当数据重复度大,比如高于 10% 的时候,就不需要对这个字段创建索引;

13、避免对经常更新的表创建过多索引

这个算是常识性的经验了,更新数据时候,不经要更新数据本身,还需要更新索引;

14、不建议用无序的值作为索引

例如身份证、UUID(在索引比较时需要转为ASCII,并且插入时可能造成页分裂)、MD5、HASH、无序长字符串等;

15、不要定义冗余或重复的索引

即对同一个字段而言,不要创建多个不同名称的索引,这样只会增加维护的成本,并不会对搜索有什么好处;

16、及时删除不再使用或者很少使用的索引

减少索引存储空间对整个表空间的开销

索引失效情况总结

1、不要在索引列上进行操作计算

计算、函数、类型转换(自动或手动)导致索引失效,上面的user表中,我们给phone创建了索引,但如果使用下面的函数进行查询,索引将会失效;

explain select * from `user` where SUBSTRING(mobile,10,2) = '12'

2、字符串查询时一定要加引号

字符串查询不加引号时存在隐式转换,将会使索引失效

3、模糊匹配

如果仅仅是尾部的模糊匹配,仍然会走索引(即后like);但如果是头部匹配,索引将会失效;

like在前

like在后

前后都有like

很多同学在实际开发中,习惯性的就写上前后都带有 like的语句,而在表数据量越来越大的情况下,效率将会非常低;

4、使用 or 连接的条件

用or分开的字段作为条件查询时,如果or前面的列有索引,但是后面的列没有索引,那么整条查询将不会使用到索引;

explain select * from `user` where mobile = '13366767812'  or email = '16678623@qq.com' 

usr表中,email由于没有建索引,所以or 的查询结果中,最终没有用到索引;

5、范围条件右边的列索引失效

对于某些联合索引,如果用到了范围查询但是查询条件的字段未按照联合索引的字段顺序,将会使得索引失效;

如下,user_name 和age创建了联合索引,使用下面这条sql分析可知

explain select * from `user` where age > 25 and user_name = '张小华'

在这种情况下,需要将范围查询条件放置语句最后;

6、不等于(!= 或者<>)索引失效

尽量避免在大数据量的查询中使用 != 这种查询

7、 is null可以使用索引,is not null无法使用索引

CREATE index idx_mobile on `user`(mobile)

分别使用下面的sql进行分析

8、使用 not in和not exists 这样的关键字导致索引失效

9、不合理的使用order by导致索引失效

其实,这个也很好理解,毕竟需要对全表数据进行排序处理,在网络上看到有说如果order by条件满足最左匹配则会正常走索引, 在当前8.0.18版本中并未出现。所以,在基于order by和limit进行使用时,要特别留意。是否走索引不仅涉及到数据库版本,还要看Mysql优化器是如何处理的。

但是使用主键进行排序,则是可以走索引的,这一点需要注意

10、其他情况

当然,还有其他一些是否走索引的规则,这与索引的类型是B-tree索引还是位图索引也有关系;

这里要说的其他,可以总结为:

Mysql优化器的其他优化策略,比如优化器认为在某些情况下,全表扫描比走索引快,则它就会放弃索引;针对这种情况,一般不用过多理会,当发现问题时再定点排查即可

尽量使用覆盖索引

最后,补充一个知识点,即使用覆盖索引

即查询要返回的结果字段中,尽可能的在索引中使用到(或全部用到),减少使用 "select * " 这样的查询;

比如下面这条语句

select address,age from `user` where user_id = '1' 

尽管使用到了主键查询,但是查询的字段 address 和 age并未包含在索引列中,所以这种情况下,innodb引擎最终需要通过回表的方式才能将数据的结果查出来;

还记得本文开头的这张图吧

当我们查询一条记录时,使用的条件为 name = ‘名字’,尽管对name创建了索引,但是name的索引结构中,其叶子节点存储的是name值以及id值,假如这时,你的查询语句中需要返回的字段不是id和name,而是address和mobile,这时,就需要拿到id再次去查询,一直查到id的索引树下的完整的记录,这就是所谓的回表;

当表的数据量足够大的时候,回表耗费的时间是很长的,这个对整体的查询响应来说一定会成为一个需要优化的点;

到此这篇关于mysql 索引使用及优化详情的文章就介绍到这了,更多相关mysql 索引优化内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • MySQL组合索引(多列索引)使用与优化案例详解

    目录 1.多列索引 2.测试案例及过程 2.1 创建一个测试数据库和数据表 2.2 添加两个单列索引 2.3 查询一条数据利用到两个列的索引 2.4 查看执行计划 2.5 然后删除以上索引,添加多列索引 2.6 再次查询 3.多列索引的使用顺序 3.1 怎么选择建立组合索引时,列的顺序 3.2 组合索引的使用规则 1.多列索引 我们经常听到一些人说"把WHERE条件里的列都加上索引",其实这个建议非常错误. 在多个列上建立单独的索引大部分情况下并不能提高MySQL的查询性能.MySQL

  • MySQL性能优化之如何高效正确的使用索引

    实践是检验真理的唯一途径,本篇只是站在索引使用的全局来定位的,你只需要通读全篇并结合具体的例子,或回忆以往使用过的地方,对整体有个全面认识,并理解索引是如何工作的,就可以了.在后续使用索引,或者优化索引时,可以从这些方面出发,进一步来加深对索引正确高效的使用. 一.索引失效 索引失效,是一个老生常谈的话题了.只要提到数据库优化.使用索引,都能一口气说出一大堆索引失效的场景,什么不能用.什么不该用这类的话,在此,我就不再一一罗列啰嗦了. 索引失效,是指表中有字段创建了索引,由于sql语句书写不当导

  • Mysql使用索引实现查询优化

    索引的目的在于提高查询效率,可以类比字典,如果要查"mysql"这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql.如果没有索引,那么你可能需要把所有单词看一遍才能找到你想要的. 1.索引的优点 假设你拥有三个未索引的表t1.t2和t3,每个表都分别包含数据列i1.i2和i3,并且每个表都包含了1000条数据行,其序号从1到1000.查找某些值匹配的数据行组合的查询可能如下所示: SELECT t1.i1, t2.i2, t3.i3 FROM t1, t2,

  • MySQL数据库优化技术之索引使用技巧总结

    本文实例总结了MySQL数据库优化技术的索引用法.分享给大家供大家参考,具体如下: 这里紧接上一篇<MySQL数据库优化技术之配置技巧总结>,进一步分析索引优化的技巧: (七)表的优化 1. 选择合适的数据引擎 MyISAM:适用于大量的读操作的表 InnoDB:适用于大量的写读作的表 2.选择合适的列类型 使用 SELECT * FROM TB_TEST PROCEDURE ANALYSE()可以对这个表的每一个字段进行分析,给出优化列类型建议 3.对于不保存NULL值的列使用NOT NUL

  • MySQL的id关联和索引使用的实际优化案例

    昨晚收到客服MM电话,一用户反馈数据库响应非常慢,手机收到load异常报警,登上主机后发现大量sql执行非常慢,有的执行时间超过了10s 优化点一: SELECT * FROM `sitevipdb`.`game_shares_buy_list` WHERE price>='2.00′ ORDER BY tran_id DESC LIMIT 10; 表结构为: CREATE TABLE `game_shares_buy_list` ( `tran_id` int(10) unsigned NOT

  • MySQL索引背后的之使用策略及优化(高性能索引策略)

    本章的内容完全基于上文的理论基础,实际上一旦理解了索引背后的机制,那么选择高性能的策略就变成了纯粹的推理,并且可以理解这些策略背后的逻辑. 示例数据库 为了讨论索引策略,需要一个数据量不算小的数据库作为示例.本文选用MySQL官方文档中提供的示例数据库之一:employees.这个数据库关系复杂度适中,且数据量较大.下图是这个数据库的E-R关系图(引用自MySQL官方手册): 图12 MySQL官方文档中关于此数据库的页面为http://dev.mysql.com/doc/employee/en

  • MySQL使用索引优化性能

    目录 1.索引问题 2.索引的存储分类 3.如何使用索引 3.1使用索引 3.2存在索引但不使用索引 4.查看索引使用情况 5.两个简单实用的优化方法 5.1定期分析表和检查表 5.2定期优化表 1.索引问题 索引是数据库优化中最常用也是最重要的手段之一,通过索引通常可以帮助用户解决大多数 的SQL性能问题.本章节将对MySQL中的索引的分类.存储.使用方法做详细的介绍. 2.索引的存储分类 MyISAM存储引擎的表数据和索引是自动分开存储的,各自是独立的一个文件:InnoDB存储引擎的表数据和

  • mysql 索引使用及优化详情

    目录 前言 mysql索引原理 mysql索引分类 索引创建语法 1.创建索引 2.查看索引 3.删除索引 4.为 username和password创建联合索引 5.给user表添加一个info的字段,并为这个字段添加全文索引 已经存在的表创建.删除索引等 1.使用ALTER TABLE语句创建索引 2.使用ALTER TABLE语句删除索引 常用的索引设计原则 索引失效情况总结 尽量使用覆盖索引 前言 索引对有一定开发经验的同学来说并不陌生,合理使用索引,能大大提升sql查询的性能,可以这么

  • 详解MySQL索引原理以及优化

    前言 本文是美团一位大佬写的,还不错拿出来和大家分享下,代码中嵌套在html中sql语句是java框架的写法,理解其sql要执行的语句即可. 背景 MySQL凭借着出色的性能.低廉的成本.丰富的资源,已经成为绝大多数互联网公司的首选关系型数据库.虽然性能出色,但所谓"好马配好鞍",如何能够更好的使用它,已经成为开发工程师的必修课,我们经常会从职位描述上看到诸如"精通MySQL"."SQL语句优化"."了解数据库原理"等要求.我

  • Mysql索引选择以及优化详解

    索引模型 哈希表 适用于只有等值查询的场景,Memory引擎默认索引 InnoDB支持自适应哈希索引,不可干预,由引擎自行决定是否创建 有序数组:在等值查询和范围查询场景中的性能都非常优秀,但插入和删除数据需要进行数据移动,成本太高.因此,只适用于静态存储引擎 二叉平衡树:每个节点的左儿子小于父节点,父节点又小于右儿子,时间复杂度是 O(log(N)) 多叉平衡树:索引不止存在内存中,还要写到磁盘上.为了让一个查询尽量少地读磁盘,就必须让查询过程访问尽量少的数据块.因此,要使用"N 叉"

  • MySQL索引介绍及优化方式

    目录 一.导致sql执行慢的原因 二.分析原因时,一定要找切入点 三.什么是索引? 四.Explain分析 1.id 2.select_type 3.table 4.type(★) 5.possible_key 6.key(★) 7.key_len 8.ref(★) 9.rows(★) 10.extra 五.优化案例 六.是否需要创建索引? 一.导致sql执行慢的原因 硬件条件限制: io吞吐量小,形成瓶颈(读取磁盘数据) 网络传输速度慢 内存不足(读取磁盘数据加载到内存) 程序设计方面: 没有

  • MySQL 索引分析和优化

    一.什么是索引? 索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存.如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录.表里面的记录数量越多,这个操作的代价就越高.如果作为搜索条件的列上已经创建了索引,MySQL无需扫描任何记录即可迅速得到目标记录所在的位置.如果表有1000个记录,通过索引查找记录至少要比顺序扫描记录快100倍. 假设我们创建了一个名为people的表: CREATE TABLE people ( p

  • Mysql 索引该如何设计与优化

    什么是索引? 数据库索引是一种数据结构,它以额外的写入和存储空间为代价来提高数据库表上数据检索操作的速度.通俗来说,索引类似于书的目录,根据其中记录的页码可以快速找到所需的内容.--维基百科 常见索引有哪些? 普通索引:最基本的索引,没有任何限制 唯一索引:与"普通索引"类似,不同的就是:索引列的值必须是唯一,但允许有空值 主键索引:它是一种特殊的索引,不允许有空值 全文索引:仅可用于 MyISAM 表,针对较大的数据,生成全文索引很耗时占空间 组合索引:为了提高多条件查询效率,可建立

  • MySQL索引的缺点以及MySQL索引在实际操作中有哪些事项

    以下的文章主要介绍的是MySQL索引的缺点以及MySQL索引在实际操作中有哪些事项是值得我们大家注意的,我们大家可能不知道过多的对索引进行使用将会造成滥用.因此MySQL索引也会有它的缺点: 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT.UPDATE和DELETE.因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件. 建立索引会占用磁盘空间的索引文件.一般情况这个问题不太严重,但如果你在一个大表上创建了多种组合索引,索引文件的会膨胀很快. 索引只是提高效

  • 美团网技术团队分享的MySQL索引及慢查询优化教程

    MySQL凭借着出色的性能.低廉的成本.丰富的资源,已经成为绝大多数互联网公司的首选关系型数据库.虽然性能出色,但所谓"好马配好鞍",如何能够更好的使用它,已经成为开发工程师的必修课,我们经常会从职位描述上看到诸如"精通MySQL"."SQL语句优化"."了解数据库原理"等要求.我们知道一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,

  • MySQL索引优化实例分析

    目录 1.数据准备 2.实例一 3.MySQL如何选择合适的索引? 4.常见 SQL 深入优化 4.1.Order by与Group by优化 4.2.分页查询优化 4.3.join关联查询优化 4.3.1.数据准备 4.3.2.MySQL 表关联常见的两种算法 4.4.in和exsits优化 4.5.count(*)查询优化 5.索引设计原则 1.数据准备 #1.建立员工表,并创建name,age,position索引,id为自增主键 CREATE TABLE `employees` (  `

  • MySQL常用命令与内部组件及SQL优化详情

    目录 1. 一些常用的 MySQL 命令 2.MySQL的内部组件结构 MySQL优化器与执行计划 SQL执行过程 词法分析器原理 查询优化器 4. SQL执行顺序 5.MySQL数据类型选择 数值类型 日期和时间 字符串 6.MySQL优化 MySQL优化分类 优化方法 SQL优化原则 EXPLAIN 查看执行计 processlist干预执行计划 SELECT语句务必指明字段名称 合理使用in和exits 关于not in 和not exists order by排序字段和where条件要匹

随机推荐