Mysql数据库索引
今天,我们来讲讲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中方式:
- 修改表结构的方式添加索引:ALTER TABLE...
- 直接创建索引:CREATE INDEX...
- 创建表的时候同时创建索引: 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数据库索引的4大类型以及相关的索引创建
以下的文章主要介绍的是MySQL数据库索引类型,其中包括普通索引,唯一索引,主键索引与主键索引,以及对这些索引的实际应用或是创建有一个详细介绍,以下就是文章的主要内容描述. (1)普通索引 这是最基本 ...
- (转)MySql数据库索引原理(总结性)
本文引用文章如链接: http://www.codinglabs.org/html/theory-of-mysql-index.html#more-100 参考书籍:Mysql技术内幕 本文主要是阐述 ...
- 知识点:Mysql 数据库索引优化实战(4)
知识点:Mysql 索引原理完全手册(1) 知识点:Mysql 索引原理完全手册(2) 知识点:Mysql 索引优化实战(3) 知识点:Mysql 数据库索引优化实战(4) 一:插入订单 业务逻辑:插 ...
- 为什么MySQL数据库索引选择使用B+树?
在进一步分析为什么MySQL数据库索引选择使用B+树之前,我相信很多小伙伴对数据结构中的树还是有些许模糊的,因此我们由浅入深一步步探讨树的演进过程,在一步步引出B树以及为什么MySQL数据库索引选择使 ...
- MySQL数据库索引之B+树
一.B+树是什么 B+ 树是一种树型数据结构,通常用于数据库和操作系统的文件系统中.B+ 树的特点是能够保持数据稳定有序,其插入与修改操作拥有较稳定的对数时间复杂度.B+ 树元素自底向上插入,这与二叉 ...
- 第二百八十八节,MySQL数据库-索引、limit分页、执行计划、慢日志查询
MySQL数据库-索引.limit分页.执行计划.慢日志查询 索引,是数据库中专门用于帮助用户快速查询数据的一种数据结构.类似于字典中的目录,查找字典内容时可以根据目录查找到数据的存放位置,然后直接获 ...
- MYSQL数据库索引类型及使用
MYSQL数据库索引类型包括普通索引,唯一索引,主键索引与组合索引,这里对这些索引的做一些简单描述: (1)普通索引 这是最基本的MySQL数据库索引,它没有任何限制.它有以下几种创建方式: 创建索引 ...
- MySQL数据库索引的底层原理(二叉树、平衡二叉树、B-Tree、B+Tree)
1.MySQL数据库索引的底层原理 https://mp.weixin.qq.com/s/zA9KvCkkte2mTWTcDv7hUg
- MySQL数据库索引常见问题
笔者看过很多数据库相关方面的面试题,但大多数答案都不太准确,因此决定在自己blog进行一个总结. Q1:数据库有哪些索引?优缺点是什么? 1.B树索引:大多数数据库采用的索引(innoDB采用的是b+ ...
- 谈谈MySQL数据库索引
在分析MySQL数据库索引之前,很多小伙伴对数据结构中的树理解不够深刻.因此我们由浅入深一步步探讨树的演进过程,再一步步引出MySQL数据库索引底层数据结构. 一.二叉树 二叉查找树也称为有序二叉查找 ...
随机推荐
- JavaScript Base64加解密
Base64加密算法是网络上最常见的用于传输8Bit字节代码的编码方式之一,大家可以查看RFC2045-RFC2049,上面有MIME的详细规范.Base64编码可用于在HTTP环境下传递较长的标识信 ...
- echarts添加点击事件
由于工作需要,需要用echarts 进行展示图表,却又个新的需求,要点击展示的地方,同时下面出现table展示内容 如图所示: 一开始找了好多博客,发现都不好用,大部分都是用到了 var ecConf ...
- 内核对象kobject和sysfs(4)——kset分析
内核对象kobject和sysfs(4)--kset分析 从狭义上来说,kset就是kobj的一个再封装而已.在封装之后,提供了针对kset之下所有kobj统一管理的一些方法. 我们还是从结构说起: ...
- Eclipse详细设置护眼背景色和字体颜色并导出
Eclipse详细设置护眼背景色和字体颜色并导出 Eclipse是一款码农们喜闻乐见的集成开发平台,但是其默认的主题和惨白的背景色实在是太刺激眼球了.下面,将给大家详细介绍如何设置成护眼主题的方法,也 ...
- MySQL系列(四)---引擎
MySql中的引擎 目录 MySQL系列(一):基础知识大总结 MySQL系列(二):MySQL事务 MySQL系列(三):索引 引擎种类 FEDERATED MRG_MYISAM MyISAM BL ...
- swift3.0 UITableView侧滑支持多选项
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableVie ...
- MySQL grant命令使用
MySQL 赋予用户权限命令的简单格式可概括为: grant 权限 on 数据库对象 to 用户 一.grant 普通数据用户,查询.插入.更新.删除 数据库中所有表数据的权利. grant sele ...
- 使用postgre数据库实现树形结构表的子-父级迭代查询,通过级联菜单简单举例
前言:开发常用的关系型数据库MySQL,mssql,postgre,Oracle,简单的增删改查的SQL语句都与标准SQL兼容,这个不用讲,那么对于迭代查询(不严格的叫法:递归查询)每种数据库都不一样 ...
- layer弹出层传值到父页面
目前做的项目中用到layer弹层传值,弹层输入框输入文本,点击确定按钮,父页面的树结构,会自动添加分组. 在此粘贴下代码,以后遇到,方便回忆,如有疑问请留言,或许会为您解答 $(document).r ...
- mysql flush操作
FLUSH语法 FLUSH [LOCAL | NO_WRITE_TO_BINLOG] flush_option [, flush_option] ... 如果您想要清除MySQL使用的部分内部缓存,您 ...