今天,我们来讲讲Mysql数据库的索引的一些东西,想必大家都知道索引能干吗?必然是查找数据表的时候,查找的速度快啊,尤其是那些几百万行的数据库,不建立索引,你是想考验用户的耐心吗?Mysql有多种存储引擎,必然,每种引擎的创建索引也是不尽相同的,比如MyISAM是B+Tree非聚集索引(secondary index)而InnoDB是B+Tree非聚集索引(clustered index),(此处有知识点:聚集索引和聚簇索引是同一个概念,只是中文不同的翻译)。下面,我打算从以下几个角度来讲解下数据库索引:

目录

1、为什么需要建立索引?

2、索引的种类以及如何建立?

3、索引的使用

4、什么情况下查询语句根本没有用到索引呢?

5、如何判断索引是否被用到?

6、使用索引来进行排序

创建本文中需要使用的表:

mysql> DROP TABLE IF EXISTS user_test;

mysql> CREATE TABLE user_test ( id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> user_name varchar(30) NOT NULL,
-> sex bit(1) NOT NULL DEFAULT b'1',
-> city varchar(50) NOT NULL,
-> age int NOT NULL)
-> ENGINE=InnoDB DEFAULT CHARSET=utf8;

mysql> explain user_test;

插入数据:

mysql> INSERT INTO user_test (user_name,sex,city,age) values ('张三',b'1','广州',26), ('王五',b'0','云南',28);

mysql> SELECT * FROM user_test;

1、为什么建立索引?

  • 可以大大加快数据的检索速度,这也是创建索引的最主要的原因
  • 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
  • 在使用分组(GROUP BY)和排序子句(ORDER BY)进行数据检索时,同样可以显著减少查询中分组和排序的时间。
  • 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
  • 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。

是不是觉得太理论了?没问题,下面我会一个个解释给你们看。

2、索引的种类以及如何建立?

创建索引的3中方式:

  1. 修改表结构的方式添加索引:ALTER TABLE...
  2. 直接创建索引:CREATE INDEX...
  3. 创建表的时候同时创建索引: INDEX...

如何删除索引呢?

DROP INDEX index_name ON table_name;

2.1 主键索引

  • ALTER TABLE table_name ADD PRIMARY KEY index_name ('column');
  • CREATE PRINARY KEY INDEX  index_name ON table_name(column(length));
  • PRINARY KEY index_name(column(length));

2.2 唯一性索引

  • ALTER TABLE table_name ADD UNIQUE index_name ('column');
  • CREATE UNIQUE INDEX index_name ON table_name(column(length));
  • UNIQUE index_name(column(length));

2.3 普通索引

  • ALTER TABLE table_name ADD INDEX index_name ('column');
  • CREATE INDEX index_name ON table_name(column(length));
  • INDEX index_name(column(length));

2.4 全文索引

  • ALTER TABLE table_name ADD FULLTEST index_name ('column');
  • CREATE FULLTEXT INDEX index_name ON table_name(column(length));
  • FULLTEXT (column);

2.5 组合索引

ALTER TABLE table_name ADD INDEX index_name ('column1',‘column2’,...);

此处有知识点:主键,也就是user_test表中的id,表中用primary key修饰的,全表就一个主键,主键的值绝对没有重复,当然也不允许为空。

       唯一性:你可以通过unique关键字设置表中某一列是唯一的,唯一也就代表,这一列中的所有的值都是独一无二的,绝对不允许重复,而且不能为空。

所以,主键是唯一的,但是唯一的并不一定是主键。

3、索引的使用

上面我们讲了如何建立索引,那建立后该怎么使用呢?

比如:我们建立个联合索引:ALTER TABLE user_test ADD INDEX idx_user (user_name , city , age);

此处有知识点:索引的建立是要有依据的,不要随便建立索引,毕竟创建索引和维护索引要耗费时间,索引也是占用物理内存的,下面会详细讲解。最好是你频繁的需要根据某一列或几列进行查询的时候,最好建立索引,比如:WHERE 后面就是你需要查找的关键字,这就是你需要创建索引。

既然建立的索引,那我们查找的时候,怎么使用呢?难道每次都要这样写:SELECT * FROM user_test WHERE username='张三' AND city='广州' AND age=26; 这样写的也太全了,能不能少些点,或者有没有办法简化一下,当然,在简化的时候有没有什么规则呢?

以上面这个索引为例,什么样的查询是有效的呢?

有效查询:

(1)全值匹配

全值匹配指的是和索引中的所有列进行匹配,如:以上面创建的索引为例,在where条件后可同时查询(user_name,city,age)为条件的数据。

此处有知识点:与where后查询条件的顺序无关,这里是很多同学容易误解的一个地方.

SQL语句:

SELECT * FROM user_test WHERE user_name='张三' AND city='广州' AND age=26;

或SELECT * FROM user_test WHERE user_name='张三' AND age=26  AND city='广州';

或 SELECT * FROM user_test WHERE  age=26  AND city='广州 AND  user_name='张三'';

这3种的查询结果是一毛一样。

(2)最左前缀匹配

联合查询包含多个列,那么在查询的时候一定要把所有的列的条件都写上去吗?少写几个行不行?答案是可以的,但是你要小心你少写的那一列。

匹配最左前缀是指优先匹配最左索引列,也就是你创建联合索引的第一列,如上面索引的第一列就是:user_name。所以你可以这样写:

SQL语句:

SELECT * FROM user_test WHERE user_name='张三' AND city='广州' ;

或SELECT * FROM user_test WHERE user_name='张三'  AND age=26;

或SELECT * FROM user_test WHERE city='广州' AND user_name='张三' ;

但是,这样写查询条件是无法使用索引的,只能全文搜索,你不可以这样写:

SQL语句:

SELECT * FROM user_test WHERE  city='广州' AND age=26;

或SELECT * FROM user_test WHERE age=26;

或SELECT * FROM user_test WHERE city='广州' ;

原因是因为你建立索引是(user_name , city , age),所以查询条件必须是包含user_name 这一最左列。

再重申一遍:满足最左前缀查询条件的顺序与索引列的顺序无关,如:(city, user_name)、(age, city, user_name)。

(3)范围值匹配

如:查询用户名以“张”开头的所有用户,这里使用了索引的第一列,

SELECT * FROM user_test WHERE user_name LIKE'张%';

但是你不能这样写:

SELECT * FROM user_test WHERE user_name LIKE'%三';

也就是说,索引必须包含最左列,最左列的前缀必须是确定的查询。

(4)前缀索引匹配

有时候被建立索引的列里面的值很长,这会增加索引的存储空间以及降低索引的效率,一种策略是可以使用hash索引,(此处有知识点:hash索引是定值索引,无法进行范围查询)还有一种就是可以使用前缀索引,前缀索引是选择字符列的前n个字符作为索引,这样可以大大节约索引空间,从而提高索引效率。

如何确定你创建的索引列的长度呢?

首先,前缀索引要选择足够长的前缀以保证高的匹配度,同时又不能太长,我们可以通过以下方式来计算出合适的前缀索引的选择长度值:

SELECT COUNT(DISTINCT index_column )/COUNT(*) FROM table_name;    ——index_column 代表你要添加索引的列。

通过以上方式来计算出前缀索引的选择性比值,比值越高说明索引的效率也就越高效。这是计算某一列整体的。如果你想计算某一列的前几个字符匹配度,那么:

SELECT COUNT(DISTINCT LEFT(index_column,1) )/COUNT(*) FROM table_name; ——表示index_column 这一列取值的第一个字符匹配度是多少,

SELECT COUNT(DISTINCT LEFT(index_column,2) )/COUNT(*) FROM table_name; ——表示index_column 这一列取值的第二个字符匹配度是多少,

通过以上语句逐步找到最接近于计算整个列的前缀索引的选择性比值,那么就可以使用对应的字符截取长度来做前缀索引了。

此时,我们就可以创建前缀索引了:

ALTER TABLE table_name ADD INDEX index_name (index_column(length));

注意:前缀索引是一种能使索引更小,更快的有效办法,但是MySql无法使用前缀索引做ORDER BY 和 GROUP BY以及使用前缀索引做覆盖扫描。

4、什么情况下查询语句根本没有用到索引呢?

既然我们已经创建了索引,那查询的时候,什么样的SQL语句才算是有效,什么样的SQL语句是无效的呢?

除了上述的全值索引,最左前缀索引,前缀索引提到的有效查询和无效查询外,下面几种情况可能会导致无效索引:

  • 索引列不能是表达式的一部分,也不能作为函数的参数,否则无法使用索引查询。

如:SELECT * FROM user_test WHERE user_name = concat(user_name, 'fei');

或SELECT * FROM user_test WHERE age+=1;

这样的语句是无法使用到索引的。

  • 如果where查询条件中有某个列的范围查询,则其右边的所有列都无法使用索引优化查询。

如:SELECT * FROM user_test WHERE user_name = ‘张三’ AND city='广%'  AND age=26;

age这一列就会被忽略的。

  • !=或者<>(不等于),会导致不走索引。

所以在查询语句中,不要对null判断,这样会导致全表查询,效率极其低。

5、如何判断索引是否被用到?

你以为你用了你创建的索引进行的查询,然而其实你并没有,

那么怎么可以看到表中创建的索引呢?两种方式:

SHOW INDEX FROM table_name;

或SHOW KEYS FROM table_name;

如何查看索引是否生效呢?

EXPLAIN +你的SQL语句;

table:显示这一行的数据是关于哪张表的

type:这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为const、eq_reg、ref、range、indexhe和ALL

possible_keys:显示可能应用在这张表中的索引。如果为空,没有可能的索引。可以为相关的域从WHERE语句中选择一个合适的语句

key: 实际使用的索引。如果为NULL,则没有使用索引。很少的情况下,mysql会选择优化不足的索引。这种情况下,可以在SELECT语句中使用USE INDEX(indexname)来强制使用一个索引或者用IGNORE INDEX(indexname)来强制MYSQL忽略索引

key_len:使用的索引的长度。在不损失精确性的情况下,长度越短越好

ref:显示索引的哪一列被使用了,如果可能的话,是一个常数

rows:MYSQL认为必须检查的用来返回请求数据的行数

Extra:关于MYSQL如何解析查询的额外信息。将在表4.3中讨论,但这里可以看到的坏的例子是Using temporary和Using filesort,意思MYSQL根本不能使用索引,结果是检索会很慢

从这张图的key,ref可以看见,三列索引生效。

上图表示用到了索引,但只有一列。

上图表示没有用到索引。

6、使用索引来进行排序

6.1 先讲解下什么是覆盖索引,下面要用到这个概念:

如果一个索引(如:组合索引)中包含所有要查询的字段的值,那么就称之为覆盖索引,如:

SELECT user_name,city,age FROM user_test WHERE  city='广州' AND age>26;

因为要查询的字段(user_name, city, age)都包含在组合索引的索引列中,所以就使用了覆盖索引查询,查看是否使用了覆盖索引可以通过执行EXPLAIN中的Extra中的值为Using index则证明使用了覆盖索引,覆盖索引可以极大的提高访问性能。

回到主题,

在排序操作中如果能使用到索引来排序,那么可以极大的提高排序的速度,要使用索引来排序需要满足以下两点即可。

  • ORDER BY子句后的列顺序要与组合索引的列顺序一致,且所有排序列的排序方向(正序/倒序)需一致。
  • 所查询的字段值需要包含在索引列中,及满足覆盖索引

通过例子来具体分析

在user_test表上创建一个组合索引:

ALTER TABLE user_test ADD INDEX index_user(user_name,city,age);

可以使用到索引排序的案例:

SELECT user_name,city,age FROM user_test ORDER BY user_name;

SELECT user_name,city,age FROM user_test ORDER BY user_name,city;

SELECT user_name,city,age FROM user_test ORDER BY user_name DESC,city DESC;

SELECT user_name,city,age FROM user_test ORDER BY user_name='张三' ORDER BY city;

第4个比较特殊一点,如果where查询条件为索引列的第一列,且为常量条件,那么ORDER BY也可以使用到索引。

说一下无法使用索引排序的:

1、sex不在索引列中

SELECT user_name,city,age FROM user_test ORDER BY user_name,sex;

2、排序列的方向不一致

SELECT user_name,city,age FROM user_test ORDER BY user_name ASC,city DESC;

3、所要查询的字段列sex没有包含在索引列中

SELECT user_name,city,age,sex FROM user_test ORDER BY user_name;

4、where查询条件后的user_name为范围查询,所以无法使用到索引的其他列

SELECT user_name,city,age FROM user_test WHERE user_name LIKE '张%' ORDER BY city;

5、多表连接查询时,只有当ORDER BY后的排序字段都是第一个表中的索引列(需要满足以上索引排序的两个规则)时,方可使用索引排序。如:再创建一个用户的扩展表user_test_ext,并建立uid的索引。

mysql> DROP TABLE IF EXISTS user_test_ext;

mysql> CREATE TABLE user_test_ext ( id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> user_name varchar(30) NOT NULL,
-> uid int NOT NULL,
-> u_password varchar(64) NOT NULL,
-> ENGINE=InnoDB DEFAULT CHARSET=utf8;

->ALTER TABLE user_test_ext  ADD INDEX index_user_ext(uid);

走索引排序:

SELECT user_name,city,age FROM user_test u LEFT JOIN user_test_ext ue ON u.id=ue.uid ORDER BY u ;

不走索引排序:

SELECT user_name,city,age FROM user_test u LEFT JOIN user_test_ext ue ON u.id=ue.uid ORDER BY ue;

参考文献:

如何理解并正确使用MySQL索引

MySQL索引背后的数据结构及算法原理

Mysql数据库索引的更多相关文章

  1. MySQL数据库索引的4大类型以及相关的索引创建

    以下的文章主要介绍的是MySQL数据库索引类型,其中包括普通索引,唯一索引,主键索引与主键索引,以及对这些索引的实际应用或是创建有一个详细介绍,以下就是文章的主要内容描述. (1)普通索引 这是最基本 ...

  2. (转)MySql数据库索引原理(总结性)

    本文引用文章如链接: http://www.codinglabs.org/html/theory-of-mysql-index.html#more-100 参考书籍:Mysql技术内幕 本文主要是阐述 ...

  3. 知识点:Mysql 数据库索引优化实战(4)

    知识点:Mysql 索引原理完全手册(1) 知识点:Mysql 索引原理完全手册(2) 知识点:Mysql 索引优化实战(3) 知识点:Mysql 数据库索引优化实战(4) 一:插入订单 业务逻辑:插 ...

  4. 为什么MySQL数据库索引选择使用B+树?

    在进一步分析为什么MySQL数据库索引选择使用B+树之前,我相信很多小伙伴对数据结构中的树还是有些许模糊的,因此我们由浅入深一步步探讨树的演进过程,在一步步引出B树以及为什么MySQL数据库索引选择使 ...

  5. MySQL数据库索引之B+树

    一.B+树是什么 B+ 树是一种树型数据结构,通常用于数据库和操作系统的文件系统中.B+ 树的特点是能够保持数据稳定有序,其插入与修改操作拥有较稳定的对数时间复杂度.B+ 树元素自底向上插入,这与二叉 ...

  6. 第二百八十八节,MySQL数据库-索引、limit分页、执行计划、慢日志查询

    MySQL数据库-索引.limit分页.执行计划.慢日志查询 索引,是数据库中专门用于帮助用户快速查询数据的一种数据结构.类似于字典中的目录,查找字典内容时可以根据目录查找到数据的存放位置,然后直接获 ...

  7. MYSQL数据库索引类型及使用

    MYSQL数据库索引类型包括普通索引,唯一索引,主键索引与组合索引,这里对这些索引的做一些简单描述: (1)普通索引 这是最基本的MySQL数据库索引,它没有任何限制.它有以下几种创建方式: 创建索引 ...

  8. MySQL数据库索引的底层原理(二叉树、平衡二叉树、B-Tree、B+Tree)

    1.MySQL数据库索引的底层原理 https://mp.weixin.qq.com/s/zA9KvCkkte2mTWTcDv7hUg

  9. MySQL数据库索引常见问题

    笔者看过很多数据库相关方面的面试题,但大多数答案都不太准确,因此决定在自己blog进行一个总结. Q1:数据库有哪些索引?优缺点是什么? 1.B树索引:大多数数据库采用的索引(innoDB采用的是b+ ...

  10. 谈谈MySQL数据库索引

    在分析MySQL数据库索引之前,很多小伙伴对数据结构中的树理解不够深刻.因此我们由浅入深一步步探讨树的演进过程,再一步步引出MySQL数据库索引底层数据结构. 一.二叉树 二叉查找树也称为有序二叉查找 ...

随机推荐

  1. maven依赖jar包更新,业务jar需同步更新(业务jar依赖API)

    背景: 环境出现问题,定位为依赖jar缺失,修改工程pom文件补充依赖jar. 更新要点说明: 依赖jar,更新提交 业务jar,也需更新提交:maven构建会把依赖jar引用进去,更新环境如果单独更 ...

  2. 解决ionic中 Action Sheets 在安卓机中的样式

    /** * Action Sheets for Android * -------------------------------------------------- */ .platform-an ...

  3. Angular页面选项卡切换要注意的toggleClass

    在第一,第二篇随笔中写到的选项卡切换,我回头看了看发现缺少了一个很重要的部分,那就是toggleClass. //在js控制器中必须写明指令,要不然在页面写了toggle-class="ac ...

  4. PocScan的搭建与使用

    安装Docker, 然后下载镜像 $ sudo curl -sSL https://get.daocloud.io/docker | sh $ sudo systemctl start docker ...

  5. 八数码问题+路径寻找问题+bfs(隐式图的判重操作)

    Δ路径寻找问题可以归结为隐式图的遍历,它的任务是找到一条凑够初始状态到终止问题的最优路径, 而不是像回溯法那样找到一个符合某些要求的解. 八数码问题就是路径查找问题背景下的经典训练题目. 程序框架 p ...

  6. Dubbo负载均衡策略

    在集群负载均衡时,Dubbo提供了多种均衡策略,缺省为random随机调用. 可以自行扩展负载均衡策略,参见:负载均衡扩展Random LoadBalance 随机,按权重设置随机概率. 在一个截面上 ...

  7. 日本語の文法⇒ day1 限る型…意向形の紹介

    1)限る型 ① 不仅仅 名+に限らず この漫画は子供に限らず.大人にも人気が高い. 最近は女性に限らず.男もダイエットに励む人が多い. ②仅仅....名+限って 当店は.本日に限って半額をセールを実施 ...

  8. css中的几个小tip(二)

    margin的塌陷现象 (一)在标准文档流中, 垂直方向存在margin的塌陷现象 先上段代码: <style type="text/css"> .box{ width ...

  9. java中Comparable和Comparator两种比较器的区别

    Comparable和Comparator接口都是为了对类进行比较,众所周知,诸如Integer,double等基本数据类型,java可以对他们进行比较,而对于类的比较,需要人工定义比较用到的字段比较 ...

  10. gitbook初体验

    前言 在早些天看sec-wiki的时候,看到有同学做了一个ctf-wiki来介绍CTF,让CTF新手能够快速入门,做成了电子书的样子,放在github上面.页面精美.简洁,让人爱不惜手. 想着自己也能 ...