一、MySQL中常见索引类型

  • 普通索引:仅加速查询
  • 主键索引:加速查询、列值唯一、表中只有一个(不可有null)
  • 唯一索引:加速查询、列值唯一(可以有null)
  • 组合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并

索引合并:使用多个单列索引组合搜索。

覆盖索引:select的数据列只用从索引中就能够取得,不必读取数据行;换句话说,查询列要被所建的索引覆盖。

普通索引

  1. -- 创建表同时添加name字段为普通索引
  2. create table tb(
  3. id int not null auto_increment primary key,
  4. name char(32) not null,
  5. index idx_name(name)
  6. );
  7.  
  8. -- 单独为表指定普通索引
  9. create index idx_name on tb(name);
  10.  
  11. -- 删除索引
  12. drop index idx_name on tb;
  13.  
  14. -- 查看索引
  15. show index from tb;
  1. Table # 表的名称
  2.  
  3. Non_unique # 如果索引为唯一索引,则为0,如果可以则为1
  4.  
  5. Key_name    # 索引的名称
  6.  
  7. Seq_in_index # 索引中的列序列号,从1开始
  8.  
  9. Column_name # 列名称
  10.  
  11. Collation # 列以什么方式存储在索引中。在MySQL中,有值‘A’(升序)或NULL(无分类)
  12.  
  13. Cardinality # 索引中唯一值的数目的估计值
  14.  
  15. Sub_part    # 如果列只是被部分地编入索引,则为被编入索引的字符的数目。如果整列被编入索引,则为NULL
  16.  
  17. Packed     #指示关键字如何被压缩。如果没有被压缩,则为NULL
  18.  
  19. Null      # 如果列含有NULL,则含有YES。如果没有,则该列含有NO
  20.  
  21. Index_type  # 用过的索引方法(BTREE, FULLTEXT, HASH, RTREE)
  22.  
  23. Comment    # 多种评注

查看索引 --> 列介绍

主键索引

主键有两个功能:加速查询 和 唯一约束(不可含null)

注意:一个表中最多只能有一个主键索引

  1. -- 创建表同时添加id字段为主键索引
  2. -- 方式一
  3. create table tb(
  4. id int not null auto_increment primary key,
  5. name char(4) not null
  6. );
  7.  
  8. -- 方式二
  9. create table tb(
  10. id int not null auto_increment,
  11. name char(4) not null,
  12. primary key(id)
  13. );
  14.  
  15. -- 给某个已经存在的表增加主键
  16. alter table tb add primary key(id);
  17.  
  18. -- 删除主键
  19. -- 方式一
  20. alter table tb drop primary key;
  21.  
  22. -- 方式二
  23. -- 如果当前主键为自增主键,则不能直接删除,需要先修改自增属性,再删除
  24. alter table tb modify id int,drop primary key;

唯一索引

唯一索引有两个功能:加速查找 唯一约束(可含一个null 值)

  1. create table tb(
  2. id int not null auto_increment primary key,
  3. name char(4) not null,
  4. age int not null,
  5. unique index idx_age (age)
  6. );
  7.  
  8. -- 给某个已经存在的表创建唯一索引
  9. create unique index idx_age on tb(age);

组合索引

组合索引是将n个列组合成一个索引
应用场景:频繁的同时使用n列来进行查询,如:select * from tb where name="pd" and id=888;

  1. create table tb(
  2. id int not null,
  3. name char(4) not null,
  4. age int not null,
  5. index idx_name_age (name,age)
  6. );
  7.  
  8. -- 给某个已经存在的表创建组合索引
  9. create index idx_name_age on tb(name,age);

二、聚集索引和非聚集索引(辅助索引)

数据库中的 B+tree 索引可以分为:聚集索引和非聚集索引

 聚集索引:innodb表/索引组织表,即表中数据按主键B+树存放,叶子节点直接存放整条数据,每张表只能有一个聚集索引。

①当你定义一个主键时,innodb 存储引擎则把它当做聚集索引;

②如果你没有定义一个主键,则 innodb 定位到第一个唯一索引,且该索引的所有列值均飞空的,则将其当做聚集索引;

③如果表没有主键或合适的唯一索引,innodb 会产生一个隐藏的行ID值6字节的行ID聚集索引。

补充:由于实际的数据页只能按照一颗B+tree进行排序,因此每张表只能有一个聚集索引,聚集索引对于主键的排序和范围查找非常有利。

非聚集索引(辅助索引):指叶节点不包含行的全部数据,叶节点除了包含键值之外,还包含一个书签连接,通过该书签再去找相应的行数据。

innodb存储引擎辅助索引获得数据的查找方式如下:

从上图中可以看出,辅助索引叶节点存放的是主键值,获得主键值后,再从聚集索引中查找整行数据。
举个例子,如果在一颗高度为3的辅助索引中查找数据,首先从辅助索引中获得主键值(3次IO),接着从高度为3的聚集索引中查找以获得整行数据(3次IO),总共需6次IO。一个表上可以存在多个辅助索引。

聚集索引与辅助索引区别:

  • 相同的是:不管是聚集索引还是辅助索引,其内部都是 B+tree 形式,即高度是平衡的,叶子结点存放着所有的数据。
  • 不同的是:聚集索引叶子结点存放的是一整行的信息,而辅助索引叶子结点存放的是单个索引字段信息。

何时使用聚集索引或非聚集索引(重要!!!):

三、测试索引

1、创建表

  1. create table userinfo(
  2. id int not null,
  3. name varchar(16) default null,
  4. age int,
  5. gender char(1) not null,
  6. email varchar(32) default null
  7. )engine=myisam default charset=utf8;

注意:MYISAM存储引擎不产生引擎事务,数据插入速度极快,为方便快速插入测试数据,等我们插完数据,再把存储类型修改为InnoDB。

2、创建存储过程

  1. create procedure insert_userinfo(in num int)
  2. begin
  3. declare i int default 0;
  4. declare n int default 1;
  5. -- 循环进行数据插入
  6. while n<=num do
  7. set i=rand()*50;
  8. insert into userinfo(id,name,age,gender,email) values(n,concat("pink",i),rand()*50,if(i%2=0,"女","男"),concat("pink",n,"@qq.com"));
  9. set n=n+1;
  10. end while;
  11. end;

3、调用存储过程,插入500万条数据

  1. call insert_userinfo(5000000);

4、修改引擎为INNODB

  1. alter table userinfo engine=innodb;

5、测试索引

①在没有索引的前提下测试查询速度

  1. select * from userinfo where id=4567890;

注意:无索引情况,mysql根本就不知道id等于4567890的记录在哪里,只能把数据表从头到尾扫描一遍,此时有多少个磁盘块就需要进行多少IO操作,所以查询速度很慢。

②在表中已经存在大量数据的前提下,为某个字段段建立索引,建立速度会很慢

  1. create index idx_id on userinfo(id);

③在索引建立完毕后,以该字段为查询条件时,查询速度提升明显

  1. select * from userinfo where id=4567890;

注意:

  1. mysql先去索引表里根据 b+树 的搜索原理很快搜索到id为4567890的数据,IO大大降低,因而速度明显提升
  2. 我们可以去mysql的data目录下找到该表,可以看到添加索引后该表占用的硬盘空间多了
  3. 如果使用没有添加索引的字段进行条件查询,速度依旧会很慢(如下图)

四、正确使用索引

数据库表中添加索引后确实会让查询速度起飞,但前提必须是正确的使用索引来查询,如果以错误的方式使用,则即使建立索引也会不奏效。
即使建立索引,索引也不会生效,例如:

  1. -- 范围查询(>、>=、<、<=、!= between...and
  2. -- = 等号
  3. select count(*) from userinfo where id=1000 -- 执行索引,索引效率高
  4.  
  5. -- >、>=、<、<=、between...and 区间查询
  6. select count(*) from userinfo where id<100; -- 执行索引,区间范围越小,索引效率越高
  7. select count(*) from userinfo where id>100; -- 执行索引,区间范围越大,索引效率越低
  8. select count(*) from userinfo where id between 10 and 500000; -- 执行索引,区间范围越大,索引效率越低
  9.  
  10. -- != 不等于
  11. select count(*) from userinfo where id!=1000; -- 索引范围大,索引效率低
  12.  
  13. -- like "%xx%"
  14. -- name字段添加索引
  15. create index idx_name on userinfo(name);
  16.  
  17. select count(*) from userinfo where name like "%xxxx%"; -- 全模糊查询,索引效率低
  18. select count(*) from userinfo where name like "%xxxx"; -- 以什么结尾模糊查询,索引效率低
  19. -- 例外:当like使用以什么开头,索引效率高
  20. select * from userinfo where name like "xxxx%";
  21.  
  22. -- or
  23. select count(*) from userinfo where id=1000 or email="xx"; -- email不是索引字段,索引此查询全表扫描
  24.  
  25. -- 例外:当or条件中有未建立索引的列才失效,以下会走索引
  26. select count(*) from userinfo where id=1000 or name="pink3"; -- idname都为索引字段时,or条件也会执行索引
  27.  
  28. -- 使用函数
  29. select count(*) from userinfo where reverse(name)="1knip"; -- name索引字段,使用函数时,索引失效
  30. -- 例外:索引字段对应的值可以使用函数,我们可以改为以下形式
  31. select count(*) from userinfo where name=reverse("1knip");
  32.  
  33. -- 类型不一致
  34. -- 如果列是字符串类型,传入条件是必须用引号引起来
  35. select count(*) from userinfo where name=123; --
  36. -- 类型一致
  37. select count(*) from userinfo where name="123"; --
  38.  
  39. -- order by
  40. -- 排序条件为索引,则select字段必须也是索引字段,否则无法命中
  41. select email from userinfo order by name desc; -- 无法命中索引
  42. select name from userinfo order by name desc; -- 命中索引

五、组合索引

组合索引:是指对表上的多个列组合起来做一个索引。

组合索引好处,简单的说有两个主要原因:

  • 一个顶三个;建了一个(a,b,c)的组合索引,那么实际等于建了(a),(a,b),(a,b,c)三个索引,因为每多一个索引,都会增加写操作的开销和磁盘空间的开销。对于大量数据的表,这可是不小的开销!
  • 索引列越多,通过索引筛选出的数据越少。有1000W条数据的表,有如下sql:select * from table where a=1 and b=2 and c=3,假设每个条件可以筛选出10%的数据,如果只有单值索引,那么通过该索引能筛选出1000W*10%=100w条数据,然后再回表从100w条数据中找到符合 b=2 and c= 3 的数据,然后再排序,再分页;如果是组合索引,通过索引筛选出1000w*10%*10%*10%=1w,然后再排序、分页,哪个更高效,一眼便知 。

最左匹配原则:从左往右依次使用生效,如果中间某个索引没有使用,那么断点前面的索引部分起作用,断点后面的索引没有起作用。

  1. select * from tb where a=1 and b=2 and c=3;
  2. -- abc三个索引都在where条件里面用到了,而且都发挥了作用
  3.  
  4. select * from tb where c=3 and b=2 and a=1;
  5. -- 这条语句列出来只想说明mysql没有那么笨,where里面的条件顺序在查询之前会被mysql自动优化,效果跟上一句一样
  6.  
  7. select * from tb where a=1 and c=3;
  8. -- a用到索引,b没有用,所以c是没有用到索引效果的
  9.  
  10. select * from tb where a=1 and b>2 and c=3;
  11. -- a用到了,b也用到了,c没有用到,这个地方b是范围值,也算断点,只不过自身用到了索引
  12.  
  13. select * from tb where a>1 and b=2 and c=3;
  14. -- a用到了,b没有使用,c没有使用
  15.  
  16. select * from tb where a=1 order by b;
  17. -- a用到了索引,b在结果排序中也用到了索引的效果
  18.  
  19. select * from tb where a=1 order by c;
  20. -- a用到了索引,但是c没有发挥排序效果,因为中间断点了
  21.  
  22. select * from tb where b=2 order by a;
  23. -- b没有用到索引,排序中a也没有发挥索引效果

、注意事项(重要)

1、避免使用select *
2、其他数据库中使用count(1)或count(列)代替count(*),而mysql数据库中count(*)经过优化后,效率与前两种基本一样
3、创建表时尽量时 char 代替 varchar
4、表的字段顺序固定长度的字段优先
5、组合索引代替多个单列索引(经常使用多个条件查询时)
6、使用连接(JOIN)来代替子查询(Sub-Queries)
7、不要有超过4个以上的表连接(JOIN)
8、优先执行那些能够大量减少结果的连接
9、连表时注意条件类型需一致
10、索引散列值不适合建索引,例:性别不适合

七、慢查询日志

慢查询日志:将mysql服务器中影响数据库性能的相关SQL语句记录到日志文件,通过对这些特殊的SQL语句分析,改进以达到提高数据库性能的目的。

慢查询日志参数:

  1. long_query_time # 设定慢查询的阀值,超出设定值的SQL即被记录到慢查询日志,缺省值为10s
  2. slow_query_log # 指定是否开启慢查询日志
  3. log_slow_queries # 指定是否开启慢查询日志(该参数已经被slow_query_log取代,做兼容性保留)
  4. slow_query_log_file # 指定慢日志文件存放位置,可以为空,系统会给一个缺省的文件host_name-slow.log
  5. log_queries_not_using_indexes # 如果值设置为ON,则会记录所有没有利用索引的查询

查看MySQL慢日志信息:

  1. -- 查询慢日志配置信息
  2. show variables like "%query%";
  3. -- 修改配置信息
  4. set global slow_query_log = on;

查看不使用索引参数状态:

  1. -- 显示参数  
  2. show variables like "%log_queries_not_using_indexes";
  3. -- 开启状态
  4. set global log_queries_not_using_indexes = on;

查看慢日志显示的方式:

  1. -- 查看慢日志记录的方式
  2. show variables like "%log_output%";
  3. -- 设置慢日志在文件和表中同时记录
  4. set global log_output="FILE,TABLE";

测试慢查询日志:

  1. -- 查询时间超过10秒就会记录到慢查询日志中
  2. select sleep(3) from userinfo;
  3. -- 查看表中的日志
  4. select * from mysql.slow_log;

八、执行计划

explain + 查询SQL:用于显示SQL执行信息参数,根据参考信息可以进行SQL优化。

  1. explain select count(*) from userinfo where id=1;

  1. 执行计划:让mysql预估执行操作(一般正确)。
  2.  
  3. type:查询计划的连接类型, 有多个参数,先从最佳类型到最差类型介绍
  4. 性能:null > system/const > eq_ref > ref > ref_or_null > index_merge > range > index > all
  5.  
  6. 慢:
  7. explain select * from userinfo where email="pink";
  8. type: ALL(全表扫描)
  9. 特别的: select * from userinfo limit 1;
  10.  
  11. 快:
  12. explain select * from userinfo where name="alex";
  13. type: ref(走索引)

EXPLAIN 参数详解

九、大数据量分页优化

执行此段代码:

  1. select * from userinfo limit 3000000,10;

优化方案:

1、简单粗暴,不允许查看这么靠后的数据。比如百度就是这样的,最多翻到76页就不让你翻了,这种方式就是从业务上解决。

2、在查询下一页时把上一页的行id作为参数传递给客户端程序,然后sql就改成了

  1. select * from userinfo where id>3000000 limit 10;

这条语句执行也是在毫秒级完成的,id>300w 其实就是让mysql直接跳到这里了,不用依次在扫描全面所有的行。

3、延迟关联

分析一下这条语句为什么慢,慢在哪里:

  1. select * from userinfo limit 3000000,10;

慢就慢在这个 * 里面,这个表除了id主键肯定还有其他字段,比如 name、age 之类的,因为select  *  所以mysql在沿着id主键走的时候要回行拿数据,走一下拿一下数据;如果把语句改成:

  1. select id from userinfo limit 3000000,10;

你会发现时间缩短了很多;然后我们在拿id分别去取10条数据就行了。语句就改成了这样:

  1. select userinfo.* from userinfo inner join
  2. (select id from userinfo limit 3000000,10) as tmp
  3. on tmp.id=userinfo.id;

PS:三种方法最先考虑第一种,其次第二种,第三种是别无选择。

MySQL之索引以及正确使用索引的更多相关文章

  1. 正确理解Mysql的列索引和多列索引

    MySQL数据库提供两种类型的索引,如果没正确设置,索引的利用效率会大打折扣却完全不知问题出在这. CREATE TABLE test ( id         INT NOT NULL, last_ ...

  2. 图解MySQL索引(三)—如何正确使用索引?

    MySQL使用了B+Tree作为底层数据结构,能够实现快速高效的数据查询功能.工作中可怕的是没有建立索引,比这更可怕的是建好了索引又没有使用到.本文将围绕着如何优雅的使用索引,图文并茂地和大家一起探讨 ...

  3. mysql索引和正确使用方式

    一.索引类型 B树索引:大部分都是,因此B树的特性限制了索引如何使用:必须看看索引的正确使用限制(含组合索引的限制)http://blog.csdn.net/lovemdx/article/detai ...

  4. mysql笔记02 创建高性能的索引

    创建高性能的索引 1. 索引(在MySQL中也叫做"键(key)")是存储引擎用于快速找到记录的一种数据结构. 2. 索引可以包含一个或多个列的值.如果索引包含多个列,那么列的顺序 ...

  5. mysql索引之四(索引使用注意规则:索引失效--存在索引但不使用索引)

    但是如果是同样的sql如果在之前能够使用到索引,那么现在使用不到索引,以下几种主要情况: 1. 随着表的增长,where条件出来的数据太多,大于15%,使得索引失效(会导致CBO计算走索引花费大于走全 ...

  6. 聚集索引、非聚集索引、聚集索引组织表、堆组织表、Mysql/PostgreSQL对比、联合主键/自增长、InnoDB/MyISAM(引擎方面另开一篇)

    参考了多篇文章,分别记录,如下. 下面是第一篇的总结 http://www.jb51.net/article/76007.htm: 在MySQL中,InnoDB引擎表是(聚集)索引组织表(cluste ...

  7. Mysql索引分析:适合建索引?不适合建索引?【转】

    数据库建立索引常用的规则如下: 1.表的主键.外键必须有索引: 2.数据量超过300的表应该有索引: 3.经常与其他表进行连接的表,在连接字段上应该建立索引: 4.经常出现在Where子句中的字段,特 ...

  8. Mysql索引介绍及常见索引的区别

    关于MySQL索引的好处,如果正确合理设计并且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL就是一个人力三轮车.对于没有索引的表,单表查询可能几十万数据就是瓶颈,而通常大型 ...

  9. MySQL性能调优——索引详解与索引的优化

    --索引优化,可以说是数据库相关优化.理解尤其是查询优化中最常用的优化手段之一.所以,只有深入索引的实现原理.存储方式.不同索引间区别,才能设计或使用最优的索引,最大幅度的提升查询效率! 一.BTre ...

随机推荐

  1. Why is processing a sorted array faster than an unsorted array(Stackoverflow)

    What is Branch Prediction? Consider a railroad junction: Image by Mecanismo, via Wikimedia Commons. ...

  2. DIV+CSS在不同浏览器中的表现

     在给员工培训DIV+CSS的过程中.他们向我提出了非常多问题,有些问题我自己也没有想到过于是抽了些时间自己进行了一番实验,所有实验在IE7和Firefox中进行: 实验一.假设一个div没有指定 ...

  3. loj 102 最小费用流

    补一发费用流的代码 %%%棒神 #include<iostream> #include<cstdio> #include<cstring> #include< ...

  4. balsamiq mockups 注册

    Name: helloWorld Key: eJzzzU/OLi0odswsqslIzcnJD88vykmpsUQCNc41hjV+7q5+AF74Ds8=

  5. JSP-Runood:JSP 客户端请求

    ylbtech-JSP-Runood:JSP 客户端请求 1.返回顶部 1. JSP 客户端请求 当浏览器请求一个网页时,它会向网络服务器发送一系列不能被直接读取的信息,因为这些信息是作为HTTP信息 ...

  6. SQL SERVER 获取给定时间段内的所有日期列表

    declare @StartDate DATETIME = '2018/08/01'declare @EndDate DATETIME ='2018/09/27'SELECT CONVERT (VAR ...

  7. scala的Class

    先看类的定义: package com.test.scala.test import scala.beans.BeanProperty /** * scala 的类 */ //定义一个scala的类 ...

  8. IIS设置HTTP To HTTPS

    转自: http://www.cnblogs.com/yipu/p/3880518.html 1.购买SSL证书,参考:http://www.cnblogs.com/yipu/p/3722135.ht ...

  9. aop 切面demo

    /** * 必须要@Aspect 和 @Component一起使用否则没法拦截通知 * 搞了好久才明白刚刚开始以为时execution里面的配置的问题 * AOP使用很简单的 */@Aspect@Co ...

  10. JVM之旅------jvm内存模型

    JVM内存管理机制 Java与C++之间有一堆由内存动态分配与垃圾收集技术所围成的“高墙”,墙外面的人想进去,墙里面的人却想出来. —— <深入理解Java虚拟机:JVM高级特性与最佳实践> ...