
- 作 用
- 应于表的SQL语句执行得更快
- 分 类
- 数据库概念
- 中文名
- 索引
- 外文名
- index
-
索引
2020-02-19 23:37:23MySQL索引笔记定义
索引是一种数据结构,通过使用索引,可以加快检索、排序。
底层通常是BTree,通过BTree可以将无序的数据相对有序。
索引的缺点是:- 如果表中数据增删改,那么索引也要修改。
- 索引占用物理空间。
- 创建索引和维护索引耗费时间。
索引分类
- 单值索引
一个索引只包含单个列,一个表可以有多个单列索引
- 唯一索引
索引列的值必须唯一,允许为空值
- 复合索引
一个索引包含多个列
基本语法
- 创建
create [unique] index index_name on table(column_name(length));
alter table_name add [unique] index [index_name] on (column_name(length)) - 删除
drop index [index_name] on table_name;
- 查看
show index from table_name;
索引结构
-
BTree索引
原理: -
Hash索引
-
full-text索引
-
R-Tree索引
建立索引注意事项
- 主键自动建立唯一索引
- 频繁作为查询的字段应该创建索引
- 外键建立索引
- 频繁更新的字段不要建立索引
- where条件里用不到的字段不创建索引
- 优先组合索引
- 表记录少不要建立索引
- 经常增删改的表不要建立索引
- 数据重复且平均的字段不要建立索引(比如说性别字段)
Explain关键字
Explain关键字用于查询MySQL如何执行SQL语句的,进而依此优化表结构或查询语句。
作用
- 表的读取顺序
- 数据读取操作的操作类型.
- 哪些索引可以使用
- 哪些索引被实际使用
- 表之间的引用
- 每张表有多少行被优化器查询
表的读取顺序
- id相同,从上到下依次执行
- id不同,由大到小依次执行
数字大的优先执行,数字相同的顺序执行
derived 衍生
select_type
- Simple简单查询
- Primary最外层查询标记为Primary
- SubQUERY子查询
- Derived
- Union联合查询
- Union Result
Type
访问类型:
最好到最差:system > const > eq_ref > ref > range > index > ALL
至少达到range级别- system表只有一条记录(等于系统表)
- const比较唯一索引(如where id = 1)
- eq_ref唯一性索引扫描(如where t1.id = t2.id)
- ref非唯一性索引扫描
- range 索引范围查询(如查询索引大于10小于20)
- index遍历全部索引
- ALL全表查询
possibble_kesy和key
possible_keys显示可能应用在这张表的索引
key实际使用的索引
如果key为null,说明索引失效或不存在。key_len
表示索引字段中使用的字节数,长度越短越好
ref
显示索引的那一列被使用了。如果可能,最好是const。
rows
根据表统计信息和索引选用情况,大致估算出找到所需的记录需要读取的行数。
extra
额外的重要信息。
-
Using Filesort :文件排序(不要出现)
-
Using temporary:使用了临时表(order by和group by,不要出现这个)
优化这两个,group by一定要按照索引的顺序和个数来。如idx_col1_col2,使用group by col1,col2,而不是group by col2,否则会使用临时表或文件排序(对索引外部排序)
-
Using index: 使用了索引
覆盖索引:查询的列就是所建的索引
索引优化
- 左连接右表建立索引,右连接左表建立索引
- join语句,小结果集驱动大结果集。
- 优先优化内层循环
- 保证join字段已经被索引
索引失效
- 全值匹配我最爱
- 最佳左前缀法则:查询从索引的最左前列并且不跳过索引中的列
- 不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫
- 存储引擎不能使用索引中范围条件右边的列
- 尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少select*
- mysq|在使用不等于**(!=或者<>)**的时候无法使用索引会导致全表扫描
- is null ,is not null也无法使用索引
- like以通配符开头(’%abc… ')mysq|索引失效会变成全表扫描的操作(使用覆盖索引可以避免通配符匹配开头索引失效的问题)
- 字符串不加单引号索引失效
- 少用or,用它来连接时会索引失效
查询优化
-
慢查询
通过开启慢查询,可以把执行速度慢的SQL筛选出来
-
小表驱动大表
-
order by 的顺序和复合索引顺序一致就不会产生filesort
如index_AB 索引,使用order by A,B不会产生filesort ,使用order by B或者order by B,A就会filesort
order by 不要和select * 一起使用
尝试提高sort_buffer_size和max_length_for_sort_data参数
慢查询
慢查询用于筛选响应时间超过阈值的语句。阈值默认是10秒,可以配合explain语句进行分析。
select variables like ‘%slow_query_log%’;
查询是否开启慢查询set global slow_query_log =1;
开启慢查询如果要永久开启慢查询,则需要更改my.cnf文件
set global long_query_time = 3;
阈值设置为3秒日志分析工具mysqldumpslow
Show Profile
mysql 提供用来分析当前会话中语句执行的资源消耗情况,用于SQL调优。
查询是否开启 show variables like ‘profiling’;
开启set profiling = on;
查看结果 show profiles;诊断SQL:show profiles cpu,block io for query ;
如果结果表status中出现以下:
则说明出现问题。 -
多个单列索引和联合索引的区别详解
2018-06-24 17:40:58那么当查询条件为2个及以上时,我们是创建多个单列索引还是创建一个联合索引好呢?他们之间的区别是什么?哪个效率高呢?我在这里详细测试分析下。 一、联合索引测试 注:Mysql版本为 5.7.20 创建测试表(表记录...背景:
为了提高数据库效率,建索引是家常便饭;那么当查询条件为2个及以上时,我们是创建多个单列索引还是创建一个联合索引好呢?他们之间的区别是什么?哪个效率高呢?我在这里详细测试分析下。
一、联合索引测试
注:Mysql版本为 5.7.20
创建测试表(表记录数为63188):
CREATE TABLE `t_mobilesms_11` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `userId` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '用户id,创建任务时的userid', `mobile` varchar(24) NOT NULL DEFAULT '' COMMENT '手机号码', `billMonth` varchar(32) DEFAULT NULL COMMENT '账单月', `time` varchar(32) DEFAULT NULL COMMENT '收/发短信时间', `peerNumber` varchar(64) NOT NULL COMMENT '对方号码', `location` varchar(64) DEFAULT NULL COMMENT '通信地(自己的)', `sendType` varchar(16) DEFAULT NULL COMMENT 'SEND-发送; RECEIVE-收取', `msgType` varchar(8) DEFAULT NULL COMMENT 'SMS-短信; MSS-彩信', `serviceName` varchar(256) DEFAULT NULL COMMENT '业务名称. e.g. 点对点(网内)', `fee` int(11) DEFAULT NULL COMMENT '通信费(单位分)', `createTime` datetime DEFAULT NULL COMMENT '创建时间', `lastModifyTime` datetime DEFAULT NULL COMMENT '最后修改时间', PRIMARY KEY (`id`), KEY `联合索引` (`userId`,`mobile`,`billMonth`) ) ENGINE=InnoDB AUTO_INCREMENT=71185 DEFAULT CHARSET=utf8 COMMENT='手机短信详情'
我们为
userId
,mobile
,billMonth
三个字段添加上联合索引!我们选择
explain
查看执行计划来观察索引利用情况:
1.查询条件为
userid
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE userid='2222'
可以通过
key
看到,联合索引有效
2.查询条件为
mobile
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE mobile='13281899972'
可以看到联合索引无效
3.查询条件为
billMonth
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE billMonth='2018-04'
联合索引无效
4.查询条件为
userid and mobile
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE userid='2222' AND mobile='13281899972'
联合索引有效
5.查询条件为
mobile and userid
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE mobile='13281899972' AND userid='2222'
在4的基础上调换了查询条件的顺序,发现联合索引依旧有效
6.查询条件为
userid or mobile
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE userid='2222' OR mobile='13281899972'
把and
换成or
,发现联合所索引无效!
7.查询条件为
userid and billMonth
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE userid='2222' AND billMonth='2018-04'
这两个条件分别位于联合索引位置的第一和第三,测试联合索引依旧有效!
8.查询条件为
mobile and billMonth
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE mobile='13281899972' AND billMonth='2018-04'
这两个条件分别位于联合索引位置的第二和第三,发现联合索引无效!
9.查询条件为
userid and mobile and billMonth
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE userid='2222' AND mobile='13281899972' AND billMonth='2018-04'
所有条件一起查询,联合索引有效!(当然,这才是最正统的用法啊!)
二、单列索引测试
创建三个单列索引:
1.查询条件为
userid and mobile and billMonth
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE userid='2222' AND mobile='13281899972' AND billMonth='2018-04'
我们发现三个单列索引只有userid
有效(位置为查询条件第一个),其他两个都没有用上。那么为什么没有用上呢?按照我们的理解,三个字段都加索引了,无论怎么排列组合查询,应该都能利用到这三个索引才对!
其实这里其实涉及到了mysql优化器的优化策略!当多条件联合查询时,优化器会评估用哪个条件的索引效率最高!它会选择最佳的索引去使用,也就是说,此处
userid 、mobile 、billMonth
这三个索引列都能用,只不过优化器判断使用userid
这一个索引能最高效完成本次查询,故最终explain展示的key为userid。
2.查询条件为
mobile and billMonth
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE mobile='13281899972' AND billMonth='2018-04'
我们发现此处两个查询条件只有mobile
生效(位置也为查询条件第一个)
3.查询条件为
userid or mobile
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE userid='2222' OR mobile='13281899972'
这次把and
换成or
,发现两个查询条件都用上索引了!我们在网上可能常常看到有人说or会导致索引失效,其实这并不准确。而且我们首先需要判断用的是哪个数据库哪个版本,什么引擎?
比如我用的是mysql5.7版本,innodb引擎,在这个环境下我们再去讨论索引的具体问题。
关于or查询的真相是:
所谓的索引失效指的是:假如or连接的俩个查询条件字段中有一个没有索引的话,引擎会放弃索引而产生全表扫描。我们从or的基本含义出发应该能理解并认可这种说法,没啥问题。此刻需要注意type类型为
index_merge
。
我查资料说mysql 5.0 版本之前 使用or只会用到一个索引(即使如上我给userid和mobile都建立的单列索引),但自从5.0版本开始引入了index_merge索引合并优化!也就是说,我们现在可以利用上多个索引去优化or查询了。index_merge作用:
1、索引合并是把几个索引的范围扫描合并成一个索引。
2、索引合并的时候,会对索引进行并集,交集或者先交集再并集操作,以便合并成一个索引。
3、这些需要合并的索引只能是一个表的。不能对多表进行索引合并。index_merge应用场景:
1.对OR语句求并集,如查询
SELECT * FROM TB1 WHERE c1="xxx" OR c2=""xxx"
时,如果c1和c2列上分别有索引,可以按照c1和c2条件进行查询,再将查询结果合并(union)操作,得到最终结果2.对AND语句求交集,如查询
SELECT * FROM TB1 WHERE c1="xxx" AND c2=""xxx"
时,如果c1和c2列上分别有索引,可以按照c1和c2条件进行查询,再将查询结果取交集(intersect)操作,得到最终结果3.对AND和OR组合语句求结果
三、结论
通俗理解:
利用索引中的附加列,您可以缩小搜索的范围,但使用一个具有两列的索引 不同于使用两个单独的索引。复合索引的结构与电话簿类似,人名由姓和名构成,电话簿首先按姓氏对进行排序,然后按名字对有相同姓氏的人进行排序。如果您知道姓,电话簿将非常有用;如果您知道姓和名,电话簿则更为有用,但如果您只知道名不姓,电话簿将没有用处。所以说创建复合索引时,应该仔细考虑列的顺序。对索引中的所有列执行搜索或仅对前几列执行搜索时,复合索引非常有用;仅对后面的任意列执行搜索时,复合索引则没有用处。
重点:
多个单列索引在多条件查询时优化器会选择最优索引策略,可能只用一个索引,也可能将多个索引全用上! 但多个单列索引底层会建立多个B+索引树,比较占用空间,也会浪费一定搜索效率,故如果只有多条件联合查询时最好建联合索引!
最左前缀原则:
顾名思义是最左优先,以最左边的为起点任何连续的索引都能匹配上,
注:如果第一个字段是范围查询需要单独建一个索引
注:在创建联合索引时,要根据业务需求,where子句中使用最频繁的一列放在最左边。这样的话扩展性较好,比如userid
经常需要作为查询条件,而mobile
不常常用,则需要把userid
放在联合索引的第一位置,即最左边
同时存在联合索引和单列索引(字段有重复的),这个时候查询mysql会怎么用索引呢?
这个涉及到mysql本身的查询优化器策略了,当一个表有多条索引可走时, Mysql 根据查询语句的成本来选择走哪条索引;
有人说where查询是按照从左到右的顺序,所以筛选力度大的条件尽量放前面。网上百度过,很多都是这种说法,但是据我研究,mysql执行优化器会对其进行优化,当不考虑索引时,where条件顺序对效率没有影响,真正有影响的是是否用到了索引!
联合索引本质:
当创建**(a,b,c)联合索引时,相当于创建了(a)单列索引**,(a,b)联合索引以及**(a,b,c)联合索引**
想要索引生效的话,只能使用 a和a,b和a,b,c三种组合;当然,我们上面测试过,a,c组合也可以,但实际上只用到了a的索引,c并没有用到!
注:这个可以结合上边的 通俗理解 来思考!
其他知识点:
1、需要加索引的字段,要在where条件中
2、数据量少的字段不需要加索引;因为建索引有一定开销,如果数据量小则没必要建索引(速度反而慢)
3、避免在where子句中使用or来连接条件,因为如果俩个字段中有一个没有索引的话,引擎会放弃索引而产生全表扫描
4、联合索引比对每个列分别建索引更有优势,因为索引建立得越多就越占磁盘空间,在更新数据的时候速度会更慢。另外建立多列索引时,顺序也是需要注意的,应该将严格的索引放在前面,这样筛选的力度会更大,效率更高。
最后的说明:
网上关于索引优化等文章太多了,针对各个数据库各个版本各种引擎都可能存在不一样的说法!
我们的SQL引擎自带的优化也越来越强大,说不定你的某个SQL优化认知,其SQL引擎在某次升级中早就自优化了。
所以要么跟进官方文档,要么关注数据库大牛的最新文章,要么在现有数据库环境下自己去亲手测试!
数据库领域的水很深。。大家加油。。共勉 ~
-
InnoDB索引
2019-08-05 16:30:091.概述 InnoDB存储引擎支持一下几种索引 B+ 树索引 全文索引 哈希索引 2.B+ 树索引 ...B+树索引可以分为聚集索引(clustered inex)和辅助索引(secondary),其内部全是B+树结构,高度平衡。...1.概述
InnoDB存储引擎支持一下几种索引
- B+ 树索引
- 全文索引
- 哈希索引
本文参考了姜承尧先生的《MySQL技术内幕InnoDB存储引擎》一书
2.B+ 树索引
B+ 树索引并不能找到给定字符的具体位置,而是将字符所在的页读取到内存中,然后再内存中查找数据。B+树中的B不是代表二叉(binary), 而是代表平衡(balance)
B+树索引可以分为聚集索引(clustered inex)和辅助索引(secondary),其内部全是B+树结构,高度平衡。聚集索引与辅助索引的区别是 : 叶子节点存放的是否是一整行的信息
聚集索引就是按照每张表的主键构建一颗B+树,叶子节点中存放的即为整张表的行记录数据,也将聚集索引的叶子节点称为数据页。这个特性决定了索引组织表中数据也是索引的一部分,每个数据页都通过一个双向链表进行连接
由于每个数据页只能按一颗B+树进行排序,因此每张表只能有一个聚集索引,查询优化器倾向于采用聚集索引,因为聚集索引能在B+树索引的叶子节点上直接找到数据。
聚集索引另一个好处是:他对于主键的排序查找和范围查找速度非常快,叶子节点就是用户查找的数据
辅助索引(也称非聚集索引)的叶子节点并不包含行记录的全部数据,叶子节点除了包含键值以外每个叶子节点中的索引行还包含了一个书签(bookmark),书签用来告诉InnoDB存储引擎哪里可以找到与索引相对应的行数据,因此书签就是相应行数据的聚集索引键。
辅助索引并不会影响聚集索引,所以每张表可以有多个辅助索引。
当通过辅助索引查找数据时,InnoDB存储引擎会遍历辅助索引并通过叶级别的指针获取指向主键索引的主键,然后通过主键索引来找到一个完整的行记录。3.Cardinality 值
对于查询条件中出现的列不一定都需要添加索引,对于反复出现重复字段的,例如性别,类型、地区等重复性高的列,他们取值范围很小,属于低选择性,这时添加索引是没有必要的,相反,对于数据几乎没有重复的字段,属于高选择性的添加B+树索引最合适。
查看索引是否属于高选择性,可以通过SHOW INDEX 中的Cardinality 值,它表示索引中不重复记录数量的预估值。他并不是一个准确值
4.B+ 树索引的使用
创建方法和单个索引创建方法一样,不同之处是有多个索引列。
CREATE TABLE t{ a INT, b INT, PRIMARY KEY (a), KEY idx_a_b (a,b) } ENGINE = INNODB
索引 idx_a_b 是联合索引,联合的列为(a,b)。
何时需要使用联合索引呢?
先看联合索引底层的实现, 多个键值对的B+树和单个键的B+树没有什么不同,都是按顺序存放的。
这样就限制了查找方式,如果我们这样查SELECT * FROM t WHERE a = xxx and b = xxx
显然这样能使用这个联合索引找到(a,b)
但是我们使用SELECT * FROM t WHERE b = xxx
查找b,就不会通过索引来查找,因为构建的B+是先根据a的大小进行排序的,索引通过b找不到位置。覆盖索引是从辅助索引中就可以得到查询记录,不需要查询聚集索引,因为辅助索引是不包含整行信息的,所以其大小远小于聚集索引。
这种情况多发生于有固定查询范围并且需要对数据整行数据进行查询,例如
SELECT * FROM TABLES WHERE ID>10000 AND ID<102000
优化的目的是减少磁盘的随机访问,并将随机访问转化为较为有序的数据访问,这对于IO-Bound类型的SQL查询语句带来性能的极大提升。MRR优化可用于range、ref、eq_ref类型的查询。
- MRR使数据访问变得较为顺序. 在查询辅助索引时, 首先根据得到的查询结果, 按照主键顺序进行排序, 并按照主键排序的顺序进行书签查找
- 减少缓冲池中页被替换的次数
- 批量处理对键值的查询操作
对于InnoDB 和 MyISAM 存储引擎的范围查询和JOIN 查询操作,MRR的工作方式如下:
- 将查询得到的辅助索引键存放于一个缓存中,这时缓存中的数据时根据辅助索引键值排序的
- 将缓存中的键值根据RowID进行排序
- 根据RowID的排序顺序来访问实际的数据文件
—————————————————————————————————————————————————————————————————————————————————
之前版本进行索引查询的时候,首先根据索引来查找记录,然后在根据WHERE条件来过滤记录,支持Index Condition Pushdown 后MySQL数据库会在取出索引的同时,判断是否可以进行WHERE条件的过滤,也就是将WHERE的部分过滤操作放在了存储引擎层。
5 全文检索
B+树索引的特点是支持前缀进行查找,例如
SELECT * FROM blog WHERE content like 'xxx%'
。对于SELECT * FROM blog WHERE content like '%xxx'
,并不支持,这种模式会导致InnoDB扫描整个表,速度会非常慢。那么现在就需要一种方案解决这个问题。那就是全文索引。InnoDB 1.2版本开始,已经全面支持了全文索引(Full-Text Search )。全文检索是将存储于数据库中的整本书或整篇文章中的任意内容单词查找出来的技术。它可以根据需要获得全文中有关章、节、段、句、词等信息,也可以进行各种统计和分析。全文索引使用倒排索引实现,辅助表中存储了单词与单词自身在一个或多个文档中的映射。将整个表中单词所在的行及其位置全部索引出来。这样在需要从中检索出行中释放含有某个单词就很快了。
InnoDB存储引擎采用 full inverted index 的方式实现全文检索。 -
我以为我对Mysql索引很了解,直到我遇到了阿里的面试官
2019-07-09 09:42:52GitHub 4.8k Star 的Java工程师成神之路 ,不来了解一下吗? GitHub 4.8k Star 的Java工程师成神之路 ,真的不来...相信很多人对于MySQL的索引都不陌生,索引(Index)是帮助MySQL高效获取数据的数据结构。 因为索引...GitHub 4.8k Star 的Java工程师成神之路 ,不来了解一下吗?
GitHub 4.8k Star 的Java工程师成神之路 ,真的不来了解一下吗?
GitHub 4.8k Star 的Java工程师成神之路 ,真的确定不来了解一下吗?
本文来自一位不愿意透露姓名的粉丝投稿
相信很多人对于MySQL的索引都不陌生,索引(Index)是帮助MySQL高效获取数据的数据结构。
因为索引是MySQL中比较重点的知识,相信很多人都有一定的了解,尤其是在面试中出现的频率特别高。楼主自认为自己对MySQL的索引相关知识有很多了解,而且因为最近在找工作面试,所以单独复习了很多关于索引的知识。
但是,我还是图样图森破,直到我被阿里的面试官虐过之后我才知道,自己在索引方面的知识,只是个小学生水平。
以下,是我总结的一次阿里面试中关于索引有关的问题以及知识点。
索引概念、索引模型
我们是怎么聊到索引的呢,是因为我提到我们的业务量比较大,每天大概有几百万的新数据生成,于是有了以下对话:
面试官:你们每天这么大的数据量,都是保存在关系型数据库中吗?
我:是的,我们线上使用的是MySQL数据库
面试官:每天几百万数据,一个月就是几千万了,那你们有没有对于查询做一些优化呢?
我:我们在数据库中创建了一些索引(我现在非常后悔我当时说了这句话)。
这里可以看到,阿里的面试官并不会像有一些公司一样拿着题库一道一道的问,而是会根据面试者做过的事情以及面试过程中的一些内容进行展开。
面试官:那你能说说什么是索引吗?
我:(这道题肯定难不住我啊)索引其实是一种数据结构,能够帮助我们快速的检索数据库中的数据。
面试官:那么索引具体采用的哪种数据结构呢?
我:(这道题我也背过)常见的MySQL主要有两种结构:Hash索引和B+ Tree索引,我们使用的是InnoDB引擎,默认的是B+树。
这里我耍了一个小心机,特意说了一下索引和存储引擎有关。希望面试官可以问我一些关于存储引擎的问题。
面试官:既然你提到InnoDB使用的B+ Tree的索引模型,那么你知道为什么采用B+ 树吗?这和Hash索引比较起来有什么优缺点吗?
我:(突然觉得这道题有点难,但是我还是凭借着自己的知识储备简单的回答上一些)因为Hash索引底层是哈希表,哈希表是一种以key-value存储数据的结构,所以多个数据在存储关系上是完全没有任何顺序关系的,所以,对于区间查询是无法直接通过索引查询的,就需要全表扫描。所以,哈希索引只适用于等值查询的场景。而B+ Tree是一种多路平衡查询树,所以他的节点是天然有序的(左子节点小于父节点、父节点小于右子节点),所以对于范围查询的时候不需要做全表扫描。
面试官:除了上面这个范围查询的,你还能说出其他的一些区别吗?
我:(这个题我回答的不好,事后百度了一下)
科普时间:B+ Tree索引和Hash索引区别 哈希索引适合等值查询,但是不无法进行范围查询 哈希索引没办法利用索引完成排序 哈希索引不支持多列联合索引的最左匹配规则 如果有大量重复键值得情况下,哈希索引的效率会很低,因为存在哈希碰撞问题
聚簇索引、覆盖索引
面试官:刚刚我们聊到B+ Tree ,那你知道B+ Tree的叶子节点都可以存哪些东西吗?
我:InnoDB的B+ Tree可能存储的是整行数据,也有可能是主键的值。
面试官:那这两者有什么区别吗? 我:(当他问我叶子节点的时候,其实我就猜到他可能要问我聚簇索引和非聚簇索引了)在 InnoDB 里,索引B+ Tree的叶子节点存储了整行数据的是主键索引,也被称之为聚簇索引。而索引B+ Tree的叶子节点存储了主键的值的是非主键索引,也被称之为非聚簇索引。
面试官:那么,聚簇索引和非聚簇索引,在查询数据的时候有区别吗?我:聚簇索引查询会更快?
面试官:为什么呢?
我:因为主键索引树的叶子节点直接就是我们要查询的整行数据了。而非主键索引的叶子节点是主键的值,查到主键的值以后,还需要再通过主键的值再进行一次查询。
面试官:刚刚你提到主键索引查询只会查一次,而非主键索引需要回表查询多次。(后来我才知道,原来这个过程叫做回表)是所有情况都是这样的吗?非主键索引一定会查询多次吗?
我:(额、这个问题我回答的不好,后来我自己查资料才知道,通过覆盖索引也可以只查询一次)
科普时间——覆盖索引 覆盖索引(covering index)指一个查询语句的执行只用从索引中就能够取得,不必从数据表中读取。也可以称之为实现了索引覆盖。 当一条查询语句符合覆盖索引条件时,MySQL只需要通过索引就可以返回查询所需要的数据,这样避免了查到索引后再返回表操作,减少I/O提高效率。 如,表covering_index_sample中有一个普通索引 idx_key1_key2(key1,key2)。当我们通过SQL语句:select key2 from covering_index_sample where key1 = ‘keytest’;的时候,就可以通过覆盖索引查询,无需回表。
联合索引、最左前缀匹配
面试官:不知道的话没关系,想问一下,你们在创建索引的时候都会考虑哪些因素呢?
我:我们一般对于查询概率比较高,经常作为where条件的字段设置索引
面试官:那你们有用过联合索引吗?
我:用过呀,我们有对一些表中创建过联合索引。
面试官:那你们在创建联合索引的时候,需要做联合索引多个字段之间顺序你们是如何选择的呢?
我:我们把识别度最高的字段放到最前面。
面试官:为什么这么做呢?
我:(这个问题有点把我问蒙了,稍微有些慌乱)这样的话可能命中率会高一点吧。。。
面试官:那你知道最左前缀匹配吗?
我:(我突然想起来原来面试官是想问这个,怪自己刚刚为什么就没想到这个呢。)哦哦哦。您刚刚问的是这个意思啊,在创建多列索引时,我们根据业务需求,where子句中使用最频繁的一列放在最左边,因为MySQL索引查询会遵循最左前缀匹配的原则,即最左优先,在检索数据时从联合索引的最左边开始匹配。所以当我们创建一个联合索引的时候,如(key1,key2,key3),相当于创建了(key1)、(key1,key2)和(key1,key2,key3)三个索引,这就是最左匹配原则。
虽然我一开始有点懵,没有联想到最左前缀匹配,但是面试官还是引导了我。很友善。
索引下推、查询优化
面试官:你们线上用的MySQL是哪个版本啊呢?
我:我们MySQL是5.7
面试官:那你知道在MySQL 5.6中,对索引做了哪些优化吗?
我:不好意思,这个我没有去了解过。(事后我查了一下,有一个比较重要的 :Index Condition Pushdown Optimization)
科普时间—— Index Condition Pushdown(索引下推) MySQL 5.6引入了索引下推优化,默认开启,使用SET optimizer_switch = ‘index_condition_pushdown=off’;可以将其关闭。官方文档中给的例子和解释如下: people表中(zipcode,lastname,firstname)构成一个索引
SELECT * FROM people WHERE zipcode=‘95054’ AND lastname LIKE ‘%etrunia%’ AND address LIKE ‘%Main Street%’;
如果没有使用索引下推技术,则MySQL会通过zipcode='95054’从存储引擎中查询对应的数据,返回到MySQL服务端,然后MySQL服务端基于lastname LIKE '%etrunia%'和address LIKE '%Main Street%'来判断数据是否符合条件。 如果使用了索引下推技术,则MYSQL首先会返回符合zipcode='95054’的索引,然后根据lastname LIKE '%etrunia%'和address LIKE '%Main Street%'来判断索引是否符合条件。如果符合条件,则根据该索引来定位对应的数据,如果不符合,则直接reject掉。 有了索引下推优化,可以在有like条件查询的情况下,减少回表次数。
面试官:你们创建的那么多索引,到底有没有生效,或者说你们的SQL语句有没有使用索引查询你们有统计过吗?
我:这个还没有统计过,除非遇到慢SQL的时候我们才会去排查
面试官:那排查的时候,有什么手段可以知道有没有走索引查询呢?
我:可以通过explain查看sql语句的执行计划,通过执行计划来分析索引使用情况
面试官:那什么情况下会发生明明创建了索引,但是执行的时候并没有通过索引呢?
我:(依稀记得和优化器有关,但是这个问题并没有回答好)
科普时间——查询优化器 一条SQL语句的查询,可以有不同的执行方案,至于最终选择哪种方案,需要通过优化器进行选择,选择执行成本最低的方案。 在一条单表查询语句真正执行之前,MySQL的查询优化器会找出执行该语句所有可能使用的方案,对比之后找出成本最低的方案。这个成本最低的方案就是所谓的执行计划。 优化过程大致如下: 1、根据搜索条件,找出所有可能使用的索引 2、计算全表扫描的代价 3、计算使用不同索引执行查询的代价 4、对比各种执行方案的代价,找出成本最低的那一个
面试官:哦,索引有关的知识我们暂时就问这么多吧。你们线上数据的事务隔离级别是什么呀?
我:(后面关于事务隔离级别的问题了,就不展开了)
感觉是因为我回答的不够好,如果这几个索引问题我都会的话,他还会追问更多,恐怕会被虐的更惨
总结&感悟
以上,就是一次面试中关于索引部分知识的问题以及我整理的答案。感觉这次面试过程中关于索引的知识,自己大概能够回答的内容占70%左右,但是自信完全答对的内容只占50%左右,看来自己索引有关的知识了解的还是不够多。
通过这次面试,发现像阿里这种大厂对于底层知识还是比较看重的,我以前以为关于索引最多也就问一下Hash和B+有什么区别,没想到最后都能问到查询优化器上面。
最后,不管本次面试能不能通过,都非常感谢有这样一次机会,可以让自己看到自己的不足。通过这次面试,我也收获了很多东西。加油!
-
Mysql | 查看表的索引
2018-02-07 19:58:40查看表的索引: show index from table_name(表名) -
深入理解MySQL索引原理和实现——为什么索引可以加速查询?
2018-04-12 09:48:26说到索引,很多人都知道“索引是一个排序的列表,在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址,在数据十分庞大的时候,索引可以大大加快查询的速度,这是因为使用索引后可以不用扫描全表来定位某... -
MySQL索引的创建与使用
2018-08-06 18:49:59索引有很多,且按不同的分类方式,又有很多种分类。不同的数据库,对索引的支持情况也不尽相同。 声明:本人主要简单示例MySQL中的单列索引、组合索引的创建与使用。 索引的创建: 建表时创建: CREATE TABLE ... -
MongoDb之TTL索引
2020-09-06 11:49:34TTL全称是(Time To Live),TTL索引能对一个单列配置过期属性来实现对文档的自动过期删除,我们可以在对字段创建索引时添加expireAfterSeconds选项将索引转换为TTL索引,该字段需要是date类型,在以下几种场景下即使... -
MySQL联合索引
2020-06-02 22:31:35联合索引概念: 联合索引又叫复合索引,即一个覆盖表中两列或者以上的索引,例如: index_name(column a,column b) 1 创建方式 执行alter table语句时创建 alter table table_name add index index_name(column_list)... -
MySQL添加、修改、删除索引以及索引的使用场景
2020-06-09 16:11:16索引是查询优化最主要的方式; 查询方式: 一种是:全表扫描; 一种是:利用数据表上建立的所以进行扫描。 1.索引类型分类 UNIQUE(唯一索引):不可以出现相同的值,可以有NULL值;( 加快查询速度,并且... -
我以为我对数据库索引十分了解,直到我遇到了阿里面试官。
2020-02-16 18:10:20索引的数据结构分析,数据库面试到索引最常见的问题分析,我总结了一下。 -
MySQL中聚集索引、非聚集索引、联合索引、覆盖索引
2020-07-13 22:44:32在《面试官:为啥加了索引查询会变快?》一文中,我们介绍了索引的数据结构,正是因为索引使用了B+树,才使得查询变快。说白了,索引的原理就是减少查询的次数、减少磁盘IO,达到快速查找所需数据的目的 我们一起来... -
mysql手册03_索引
2020-08-14 19:45:14mysql手册03_索引 索引是帮助MySQL进行高效率数据查询的数据结构 索引的优势和劣势: 优势:提高数据检索和排序的效率 劣势:索引占用空间,更新表时,MySQL不仅要更新数据,还要更新索引信息。 BTREE结构: 以5叉... -
mysql 联合索引生效的条件、索引失效的条件
2019-02-23 10:11:301.联合索引失效的条件 联合索引又叫复合索引。两个或更多个列上的索引被称作复合索引。 对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。例如索引是key... -
详述 Elasticsearch 通过范围条件查询索引数据的方法
2019-04-05 11:15:59在使用 Elasticsearch 的时候,我们可能会遇到需要**以范围为条件查询索引数据**的需求。有两种方法可以实现我们的需求: - 第一种:在服务器或者终端,使用命令来查询索引数据; - 第二种:编写程序,通过 Elastic... -
数据库索引原理,及MySQL索引类型
2018-08-31 21:08:40MySQL索引类型一览 让MySQL高效运行起来 本文介绍了七种MySQL索引类型。在数据库表中,对字段建立索引可以大大提高查询速度。通过善用这些索引,可以令MySQL的查询和运行更加高效。 索引是快速搜索的关键。MySQL... -
python中找出numpy array数组的最值及其索引
2018-02-13 16:24:40python中找出numpy array数组的最值及其索引 在list列表中,max(list)可以得到list的最大值,list.index(max(list))可以得到最大值对应的索引 但在numpy中的array没有index方法,取而代之的是where,其又是list... -
MYSQL的索引(主键索引、唯一索引、普通索引、全文索引)
2019-03-28 17:53:09一、MYSQL索引的分类 索引用于快速查找具有特定列值的行。如果没有索引,MySQL必须从第一行开始,然后读取整个表以查找相关行。表越大,成本越高。如果表中有相关列的索引,MySQL可以快速确定要在数据文件中间... -
聚集索引,非聚集索引,覆盖索引 原理
2018-08-28 11:37:34「数据库」和「数据库索引」这两个东西是在服务器端开发领域应用最为广泛的两个概念,熟练使用数据库和数据库索引是开发人员在行业内生存的必备技能 使用索引很简单,只要能写创建表的语句,就肯定能写创建索引的... -
Neo4j 创建索引、删除索引、查询索引
2019-04-11 19:56:571.创建索引 给 Label 为 Person 的节点的 name 属性上创建索引,CQL语句如下所示: CREATE INDEX ON :Person(name) 运行截图如下所示: 重复执行上述CQL语句,再次创建索引,不会报错,但是没有再创建索引。 ... -
普通索引 唯一索引 主键索引 候选索引
2017-03-14 20:59:30普通索引 最基本的索引类型,没有唯一性之类的限制。普通索引可以通过以下几种方式创建: 创建索引,例如CREATE INDEX ON tablename (列的列表); 修改表,例如ALTER TABLE tablename ADD INDEX [索引的名字] (列... -
数据库索引
2018-11-11 09:27:25说白了,数据库的索引问题就是查找问题 数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询,更新数据库中表的数据.索引的实现通常使用B树和变种的B+树(mysql常用的索引就是B+树) 除了数据之外,数据库... -
联合索引
2020-09-15 23:06:32MySQL可以使用多个字段同时建立一个索引,叫做联合索引.在联合索引中,如果想要命中索引,需要按照建立索引时的字段顺序挨个使用,否则无法命中索引。 MySQL使用索引时需要索引有序,假设现在建立了"name,age,school"的... -
MySQL的索引
2020-09-02 18:01:07什么是索引? 索引是帮助MySQL提高获取数据的数据结构,换一句话讲就是:排好序的快速查找的数据结构。 1、索引的分类 MySQL主要的几种索引类型:1.普通索引、2.唯一索引、3.主键索引、4.组合索引、5.全文索引。 1、... -
mysql 创建 主键索引 唯一索引 全文索引 多列索引 添加索引
2016-09-23 15:06:14查看索引 show index from 数据库表名 alter table 数据库add index 索引名称(数据库字段名称) PRIMARY KEY(主键索引) ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` ) UNIQUE(唯一索引) ... -
MySQL创建索引、重建索引、查询索引、删除索引
2019-05-31 16:27:391、创建索引 索引的创建可以在CREATE TABLE语句中进行,也可以单独用CREATE INDEX或ALTER TABLE来给表增加索引。 以下命令语句分别展示了如何创建主键索引(PRIMARY KEY)、 唯一索引(UNIQUE)、 全文索引...
-
物联网基础篇:快速玩转MQTT
-
MySQL删除30天以前的数据(PHP)
-
jn82901336.github.io-源码
-
PHP类和对象
-
项目经理成长之路
-
QHVlcPlayer.rar
-
sakura主题细节修改(2):HTML自定义
-
MaxScale 实现 MySQL 读写分离与负载均衡
-
实现 MySQL 读写分离的利器 mysql-proxy
-
项目管理工具与方法
-
2021 年该学的 CSS 框架 Tailwind CSS 实战视频
-
使用 Linux 平台充当 Router 路由器
-
抖音任务点赞平台源码.zip
-
PHP SOCKET编程
-
华为1+X认证——网络系统建设与运维(初级)
-
动车组轴温检测系统仿真设计.zip
-
网上行销原则.txt
-
MySQL 主从复制 Replication 详解(Linux 和 W
-
基于SpringBoot+MyBatis的电影购票系统
-
PPT大神之路高清教程