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

开发笔记:Mysql知识汇总之常用索引及sql优化

本文由编程笔记#小编为大家整理,主要介绍了Mysql知识汇总之常用索引及sql优化相关的知识,希望对你有一定的参考价值。
本文由编程笔记#小编为大家整理,主要介绍了Mysql知识汇总之常用索引及sql优化相关的知识,希望对你有一定的参考价值。





写在前边:索引在mysql中是极其重要的,它可以大大提高数据查询的速度,而且使用起来灵活方便,本章大概聊一下常用的索引类型以及sql优化相关的知识



你懂得越多,你不懂越多




alt


索引类型


mysql的索引类型从逻辑角度大概可分为:普通索引(normal)、唯一索引(unique)、主键索引、组合索引。


普通索引(normal)


普通索引可以理解为单个字段的索引,可以使用如下命令创建


CREATE INDEX index_name ON table(column(length))

或者修改通过表结构的方式创建


ALTER TABLE table_name ADD INDEX index_name ON (column(length))

或者在创建表的时候创建


CREATE TABLE `table` (
    `id` int(11NOT NULL AUTO_INCREMENT ,
    `name` char(255CHARACTER NOT NULL ,
    `content` text CHARACTER NULL ,
    `time` int(10NULL DEFAULT NULL ,
    PRIMARY KEY (`id`),
    INDEX index_name (title(length))
)

唯一索引(unique)


与普通索引的区别是,索引列的值必须是唯一的,但是可以为空
创建方式:


直接创建:


CREATE UNIQUE INDEX indexName ON table(column(length))   

修改表结构方式:


ALTER TABLE table_name ADD UNIQUE indexName ON (column(length))

创建表时创建


CREATE TABLE `table` (
    `id` int(11NOT NULL AUTO_INCREMENT ,
    `title` char(255CHARACTER NOT NULL ,
    `content` text CHARACTER NULL ,
    `time` int(10NULL DEFAULT NULL ,
    UNIQUE indexName (title(length))
);

主键索引


是唯一索引的一种,要求索引列不能为空值,一般是建表是创建


CREATE TABLE `table` (
    `id` int(11NOT NULL AUTO_INCREMENT ,
    `title` char(255NOT NULL ,
    PRIMARY KEY (`id`)
);

组合索引


是指为多个字段创建的索引,遵循最左匹配原则,比如索引列包括a,b,c,那么相当于创建了3个组合索引:a,b,ca,ba
创建方式:


ALTER TABLE `table` ADD INDEX a_b_c (a,b,c); 

除了这些索引之外,其实在数据结构角度和物理存储角度还包括以下几种



  • 数据结构角度:hash索引、B+树索引、全文索引、R-树索引


  • 物理存储角度:聚集索引、非聚集索引



sql优化


Explain


explain想必大家都用过吧,用来解释sql语句,是否使用了索引,使用了哪种索引,接下来就看一下explain都有哪些字段。



【Mysql知识汇总】之常用索引及sql优化

alt


id:
select 识别标识符。这是select 查询序列号,查询序列号即为sql语句执行的顺序,比如下面这个sql:


EXPLAIN SELECT * from (SELECT * from t2 limit 10as d


【Mysql知识汇总】之常用索引及sql优化

alt


select_type: select 类型,他有以下几种值



  • simple:他表示简单的select ,没有union和子查询


  • primary:最外面的select ,在有子查询的语句中,最外面的select 查询就是primary,


  • union:union语句的第二个或者说是后面那一个,现在执行一条语句



EXPLAIN select * from t2 union select *from t2 limit 10

结果为:



【Mysql知识汇总】之常用索引及sql优化

alt



  • dependent union:union 中的第二个或者后面的select语句,取决于外面的查询


  • union result:union 的结果如上所示



table


输出的行所用的表,这个参数显而易见,容易理解


type


连接类型,有多个参数,先从最佳类型到最差类型介绍



  • system:表示仅有一行,这是const类型的特例,平时不会出现,和这个也可以忽略不计


  • const:表最多有一行匹配,const用于比较primary key或者unique索引。因为只匹配一行数据,所以很快,记住一定是用到primary key或者unique,并且只检索出两条数据的情况下才会是const,看下面这条语句

    EXPLAIN select * from t2 limit 1


    【Mysql知识汇总】之常用索引及sql优化

    alt

    虽然只搜索一条数据,但是因为没有用到指定的索引,所以不会使用const,继续看看下面这个

    EXPLAIN select * from t2 where id=827


    【Mysql知识汇总】之常用索引及sql优化

    alt

    id是主键,所以使用了const,所以说可以理解为copnst是最优化的;


  • eq_ref:表间连接使用等值比较的列索引为主键或唯一非空索引时,看下面语句

    EXPLAIN select * from t1,t2  WHERE t1.id=t2.t1_id


    【Mysql知识汇总】之常用索引及sql优化

    alt


  • ref:对于每个来自于前面的表的行组合,所有匹配索引值的行将从这张表中读取。如果联接只使用键的最左边的前缀,或如果键不是unique或primary key ,则使用ref。如果使用的键仅仅匹配少量行,该联接类型是不错的。

    EXPLAIN select * from t1,t2  where t1.status=t2.status


    【Mysql知识汇总】之常用索引及sql优化

    alt


  • ref_or_null:该联接类型如同ref,但是添加了mysql可以专门搜索包含NULL值得行。在解决子查询中经常使用该联接类型的优化。


  • index_merge:该联接类型表示使用了索引合并优化方法,在这种情况下,key列包含了使用的索引的清单,key_len包含了使用的索引的最长的关键元素。


  • unique_subquery


  • index_subquery


  • range:给定范围内的检索,使用一个索引来检查行。看下面两条语句

    EXPLAIN select * from t1  WHERE user_id in ('1001','1002')



    alt

    EXPLAIN select * from t1  WHERE driver_id in ('110','111')



    alt

    user_id有索引,driver_id没有索引,结果是第一条语句的联接类型是range,第二个是ALL,以为是一定范围,所以像between也可以这样联接,很明显


  • index:该联接类型与ALL相同,除了只有索引树被扫描,这通常比ALL快,因为索引文件通常比数据文件小。(也就是说虽然all和index都是读全表,但是index是从索引中读取的,而all是从硬盘中读取的)



当查询只使用作为单索引部分的列时,Mysql可以使用该联接类型。



  • ALL:对于每个来自于优先前的表的行组合,进程完整的表扫描。如果标识第一个没标记const的表,这通常不好,并且通常在它情况下很差,通常可以增加更多的索引而不要使用ALL,使得行能基于前面的表中的常数值或值被检索出。



possible_keys


提示使用哪个索引会在该列表中找到行,不太重要


key


mysql 使用的索引,简单且重要


key_len


mysql使用的索引长度


ref


ref列显示使用哪列或常数与key一起从表中选择行。


rows


显示mysql 执行查询的行数,简单且重要,数值越大越不好,说明没有用好索引。


extra


该列包含mysql解决查询的详细信息



  • distinct:mysql发现第一个匹配行后,停止为当前的行组合搜索更多的行


  • Not exists


  • range checked each record:没有找到适合的索引。


  • using filesort:mysql手册是这么解释”mysql 需要额外的一次传递,以找出如何安排顺序检索行,通过根绝联接类型浏览所有行并为所有匹配where子句的行保存排序关键字和行的指针来完成排序。然后关键字被排序,并按排序顺序检索行“


  • using index:只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的信息。



explain select * from uspace_uchome where uid=1的extra为using index(uid建有索引)


explain select * from uspace_uchome where uid=1的extra为using index(groupid 未建立索引)



  • using temporary
    :为了解决查询,mysql需要创建一个临时表来容纳结果,典型情况如查询包含客户以按不同情况列出列的group by和order by子句时.出现using temporary就说明语句需要优化。


  • using where:where 子句用于限制哪一个行匹配下一个表或发送到客户。除非你专门从表中索取或检查所有行,如果extra值不为using where 并且表示联接类型为ALL或index,查询可能会有一些错误。


  • using sort_union(),using union(…),using intersect(….):这些函数说明如何为index_merge联接类型合并索引扫描


  • using index fro group-by:类似于访问表的using index方式,using index for group-by 表示mysql发现了一个索引,可以用查询group by或distinct查询的所有列,而不要额外搜索硬盘访问实际的表。并且,按最有效的方式使用索引,以便于对每个组,只读取少量索引条目。



使用索引


提高性能优化的索引:覆盖索引、最左前缀索引、索引下推


覆盖索引:


在介绍覆盖索引之前,我们先了解下什么是回表,比如有一个user表,有id和name索引,然后有一条sql:


select * from user where name='aaa'

这个时候执行流程是先找到name索引上的“aaa”,然后找到对应的id,最后根据id索引找到对应user记录,这样先查name索引树,又回到主建索引树进行搜索的过程,就叫做回表覆盖索引也就是解决回表的问题,其实也比较好理解,如果我直接select id就不会去主建索引树查询,因为通过name索引可以直接获取到id,其实通过覆盖索引可以减少树的搜索次数,显著提高查询性能。也是在实际开发过程中经常用来优化的手段。


最左前缀索引


-最左匹配原则是针对联合索引,查询时会从左到右依次查找索引,但是需要注意的是如果sql中有范围查询 (>、<、between、like左匹配)等就不能进一步匹配了,后续退化为线性查找。


比如有联合索引(a,b,c,d),查询条件为a=1 and b=2 and c>3 and d=4,根据最左匹配原则,会依次命中a、b、c,但是无法命中d,因为c是范围查询,d已经无法进行排序了。


索引下推(index condition pushdown )


指的是可以在遍历的过程中就对包含的字段先做判断,直接过滤掉不符合条件的数据,减少回表操作,是在Mysql 5.6之后引入的。


比如下面这条sql:


select * from t where a>10 and a<20 and b='xx'

5.6之前的执行过程是:



  • 1、判断a是否大于10且小于20


  • 2、如果步骤1不满足条件,则进行下一条记录。如果步骤1满足条件,则从a的索引树中取得对应的主键进行回表操作


  • 3、回表操作取得整行数据,取b的值判断是否等于’xx’,如果是,取出数据。重复步骤1和步骤2,直至a大于等于20终止



上面的执行过程中如果满足步骤1的数据有100条,但同时满足t.b='xx’的数据只有10条,数据库却需要回表100次。


引入索引下推后,执行过程如下:



  • 1、判断a是否大于10且小于20


  • 2、如果步骤1不满足条件,则进行下一条记录。如果步骤1满足条件,则继续判断b是否等于’‘xx’。如果不满足,则进行下一条记录,如果满足,则从a的索引树中取得对应的主键进行回表操作,取出数据


  • 3、重复步骤1和步骤2,直至a大于等于20终止



总结:在引入索引下推后,整个过程只需要回表10次,大大减少了回表操作。


需要注意的点



  • 不要在索引字段上进行函数操作或使用表达式,比如:

    select * from table where left(title, 6) = ‘aaa’  //使用函数,不会使用索引
    select * from table where id + 1 = 10000  //使用表达式,不会使用索引


  • 隐式类型转换不会走索引

    select * from t where id = 1

    如果id字段是字符串类型,那么这个查询不会使用索引,因为Mysql底层会使用CAST函数进行类型转换,那么使用函数将不会走索引。



Tips


下列几种情况下有可能使用到索引:



  • 对于创建的多列索引,只要查询条件使用了最左边的列,索引一般就会被使用。


  • 对于使用like的查询,后面如果是常量并且只有%不在第一个字符,索引才可能被使用。


  • 如果使用column_name is null将使用索引



下列几种情况不适合建立索引



  • 表记录太小


  • 经常增删改的表


  • 数据重复且分布平均的表字段


  • 如果条件中有or,即使其中有条件有索引也不会使用。


  • 对于多列索引,不是使用的第一部分,则不会使用索引。


  • like查询是以%开头


  • 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来。否则不使用索引。


  • 如果mysql估计使用全表扫描要比使用索引快,则不使用索引。



下列几种情况适合添加索引:



  • 主键自动建立唯一索引


  • 频繁作为查询条件的字段应该建立索引


  • 查询中与其他表关联的字段,外键关系建立索引


  • 频繁更新的字段不适合创建索引-更新表的同时,同步更新索引


  • Where条件里用不到的字段不创建索引


  • 单键/组合索引的选择问题,who?(在高并发下倾向创建组合索引)


  • 查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度


  • 查询中统计或者分组字段



索引失效:



  • 全值匹配


  • 最佳左前缀法则


  • 不在索引列上做任何操作(查询条件中含有函数或表达式)


  • 存储引擎不能使用索引中范围条件右边的列


  • 尽量使用覆盖索引,减少select *


  • mysql在使用不等于的时候无法使用索引会导致全表索引


  • Is null,is not null也无法使用索引


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


  • 字符串不加单引号索引失效少用or,用它来连接时会索引失效





推荐阅读
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
    本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
author-avatar
pS看云梦山水Tn
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有