热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

mysql 索引使用及优化详情【mysql特性】

这篇文章主要介绍了mysql 索引使用及优化详情,合理使用索引,能大大提升sql查询的性能,可以这么讲,随着业务数据量的不断增长,优化系统的响应速度,很大程度上可以说就

前言

索引对有一定开发经验的同学来说并不陌生,合理使用索引,能大大提升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 索引优化内容请搜索编程笔记以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程笔记!


推荐阅读
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 近年来,大数据成为互联网世界的新宠儿,被列入阿里巴巴、谷歌等公司的战略规划中,也在政府报告中频繁提及。据《大数据人才报告》显示,目前全国大数据人才仅46万,未来3-5年将出现高达150万的人才缺口。根据领英报告,数据剖析人才供应指数最低,且跳槽速度最快。中国商业结合会数据剖析专业委员会统计显示,未来中国基础性数据剖析人才缺口将高达1400万。目前BAT企业中,60%以上的招聘职位都是针对大数据人才的。 ... [详细]
  • Excel数据处理中的七个查询匹配函数详解
    本文介绍了Excel数据处理中的七个查询匹配函数,以vlookup函数为例进行了详细讲解。通过示例和语法解释,说明了vlookup函数的用法和参数的含义,帮助读者更好地理解和运用查询匹配函数进行数据处理。 ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • 数字账号安全与数据资产问题的研究及解决方案
    本文研究了数字账号安全与数据资产问题,并提出了解决方案。近期,大量QQ账号被盗事件引起了广泛关注。欺诈者对数字账号的价值认识超过了账号主人,因此他们不断攻击和盗用账号。然而,平台和账号主人对账号安全问题的态度不正确,只有用户自身意识到问题的严重性并采取行动,才能推动平台优先解决这些问题。本文旨在提醒用户关注账号安全,并呼吁平台承担起更多的责任。令牌云团队对此进行了长期深入的研究,并提出了相应的解决方案。 ... [详细]
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • 企业数据应用挑战及元数据管理的重要性
    本文主要介绍了企业在日常经营管理过程中面临的数据应用挑战,包括数据找不到、数据读不懂、数据不可信等问题。针对这些挑战,通过元数据管理可以实现数据的可见、可懂、可用,帮助业务快速获取所需数据。文章提出了“灵魂”三问——元数据是什么、有什么用、又该怎么管,强调了元数据管理在企业数据治理中的基础和前提作用。 ... [详细]
  • 本文介绍了Oracle存储过程的基本语法和写法示例,同时还介绍了已命名的系统异常的产生原因。 ... [详细]
  • 分享css中提升优先级属性!important的用法总结
    web前端|css教程css!importantweb前端-css教程本文分享css中提升优先级属性!important的用法总结微信门店展示源码,vscode如何管理站点,ubu ... [详细]
  • 统一知识图谱学习和建议:更好地理解用户偏好
    本文介绍了一种将知识图谱纳入推荐系统的方法,以提高推荐的准确性和可解释性。与现有方法不同的是,本方法考虑了知识图谱的不完整性,并在知识图谱中传输关系信息,以更好地理解用户的偏好。通过大量实验,验证了本方法在推荐任务和知识图谱完成任务上的优势。 ... [详细]
  • 本文介绍了互联网思维中的三个段子,涵盖了餐饮行业、淘品牌和创业企业的案例。通过这些案例,探讨了互联网思维的九大分类和十九条法则。其中包括雕爷牛腩餐厅的成功经验,三只松鼠淘品牌的包装策略以及一家创业企业的销售额增长情况。这些案例展示了互联网思维在不同领域的应用和成功之道。 ... [详细]
  • MySQL多表数据库操作方法及子查询详解
    本文详细介绍了MySQL数据库的多表操作方法,包括增删改和单表查询,同时还解释了子查询的概念和用法。文章通过示例和步骤说明了如何进行数据的插入、删除和更新操作,以及如何执行单表查询和使用聚合函数进行统计。对于需要对MySQL数据库进行操作的读者来说,本文是一个非常实用的参考资料。 ... [详细]
  • HashMap的扩容知识详解
    本文详细介绍了HashMap的扩容知识,包括扩容的概述、扩容条件以及1.7版本中的扩容方法。通过学习本文,读者可以全面了解HashMap的扩容机制,提升对HashMap的理解和应用能力。 ... [详细]
  • 在加载一个第三方厂商的dll文件时,提示“找不到指定模块,加载失败”。由于缺乏必要的技术支持,百思不得期间。后来发现一个有用的工具 ... [详细]
author-avatar
圣峰冰寒_869
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有