重点参考:html
必定要仔细看其中讲的索引原理!!!本文中都是简单的总结。java
参考:mysql
MySQL索引选择及规则整理:仔细看里面提到的“前缀索引”segmentfault
整体来讲,索引类型只存在:聚簇索引 和 非聚簇索引(二级索引)。
联合索引
、前缀索引
都是非聚簇索引
中的更明确分类。
覆盖索引
(我的以为)并不算一种索引类型,而是基于非聚簇索引
的原理对查询的一种优化方式。markdown
“回表查询”:
回到聚簇索引取行数据。1次回表查询须要2次B+树的遍历查找
,因此应该尽可能避免回表(不要刻意避免,以避免得不偿失)。函数
为何InnoDB只有一个聚簇索引,而不将全部索引都使用聚簇索引?
由于“叶子节点中存放了该索引对应的行记录的完整数据”,若是全部索引都是聚簇索引,意味着每一个叶子节点都保存一份数据,会形成数据的冗余和资源的浪费。性能
哪些列索引能够是聚簇索引?
InnoDB中通常都是PK;
若是不存在PK,则会选择惟一非空索引
代替。
若是不存在惟一非空索引
,则会隐式定义一个PK
来做为汇集索引。mysql索引
建议向聚簇索引中插入有序的值
例如,聚簇索引列是pk,建议选择int, auto_increment
,而避免使用无序的UUID
。
a)无序的pk
使数据存储稀疏,这就会出现聚簇索引有可能有比全表扫面更慢
b)无序的pk
新插入数据时,可能须要插入到某些列的中间,这可能致使数据页
分裂,从而移动行数据。
c)有序的pk值
很好的避免了上述无序的pk
带来的问题。
(通常都指的是 单列索引,相对 联合索引 而言)
为何叫二级索引
的一种解释
二级索引须要两次B+树的遍历查找才能取到数据。
第一次经过二级索引找到索引的叶子节点,从而找到数据的主键(或者其聚簇索引的索引值),而后用该主键去聚簇索引中再次经过B+树查找到完整的行数据。因此,“回表”会有2次B+树的查找过程。
为何辅助索引
使用“聚簇索引的索引值”做为pointer,而不是使用"地址值"做为pointer?
使用"地址值"带来的好处:
1)"地址值"比"聚簇索引的索引值"占用更少的空间
2)减小了1次B+树查找的过程。
可是,相应的须要维护辅助索引
,这是一个至关困难的维护工做。
使用“聚簇索引的索引值”做为pointer时,当出现行移动或者数据页分裂时,辅助索引不受影响(即不须要维护 辅助索引)
辅助索引
中的最左前缀匹配原则
单列辅助索引遇到<, <=, =, >, >=, between, like(右边模糊)
能够用到索引。
假设存在索引(col_1)
,例如liek 'xxx%'
是能够用到辅助索引的。
属于辅助索引
,只是:将多列做为索引,默认多列往右匹配。
联合索引
中的最左前缀匹配原则
联合索引遇到范围查询时就中止匹配。(待商榷)
假设存在索引(a, b, c, d)
,那么where a =1 and b = 2 and c > 3 and d = 4
中,a, b
能够用到联合索引。此时,建立(a, b, d, c)
索引更合适,而且因为查询优化器的优化 where中 a,b,d能够任意顺序。
(扩展疑问:以上联合索引中,c可否用到索引?参考后面提到的索引下推
)
优化器对单列辅助索引
与联合索引
的选择
例如存在单列辅助索引(col_1)
和 联合索引(col_1, col_2)
,在执行查询时,优化器是选择 单列辅助索引 仍是 联合索引,主要仍是须要结合实际SQL。
where col_1=xxx
,可能会选择 单列辅助索引。(不肯定,具体仍是看 explain)
where col_1=xxx order by col_2
,选择 联合索引,由于col_2
是在col_1
的基础上排序,避免了进行1次filesort
。
前缀索引能有效减少索引文件的大小,提升索引的速度。
可是前缀索引也有它的坏处:
1)不能在 ORDER BY 或 GROUP BY 中使用前缀索引
2)也不能把它们用做覆盖索引(Covering Index)。
针对2)
的我的理解,前缀索引的叶子节点记录的也只是"主键"和"前缀值",须要回表才能拿到完整的值。
例如,假设须要建立 article_title列的索引,可是 article_title 可能很长(索引占用空间多),那么能够只取article_title的前N个字符做为 前缀索引。
语法:CREATE INDEX index_name ON table_name(column_name(length));
InnoDB存储引擎支持覆盖索引,即从辅助索引中就能够获得查询的记录,而不须要查询汇集索引中的记录。所以:
1) 使用覆盖索引能够避免回表查询(减小了大量的IO操做)
例如,假设存在索引(col_1, col_2, col_3)
,现有查询SQL select * from table where col_1 = xx
。若是在需求知足的状况下,能够有效利用覆盖索引来优化查询SQL select col_1, col_2, col_3 from table where col_1 = xx
。
2) 有助于统计
例如,假设存在非聚簇索引(name)
和聚簇索引(id)
,在执行统计查询select count(*)
时,查询优化器可能会选择使用 非聚簇索引。由于,非聚簇索引 要远小于 聚簇索引。
暂时还没法理解2)
,特别是 汇集索引、辅助索引、覆盖索引、联合索引 中基于 联合索引 & count 的示例更不理解~~~
student表:PRIMARY KEY (
id
), KEYidx_name
(name
), KEYidx_school_age
(school
,age
)`执行sql:select count(*) from student
优化器会选用idx_name
这个辅助索引。(具体看 explain)执行SQL:select count(*) from student where age > 10 and age < 15
优化器会选用idx_school_age
这个辅助索引。(具体看 explain)
忽略。
相比单例辅助索引
的最左前缀匹配原则,联合索引 是从左往右依次比较列。
例如col_1, col_2, col_3, col_4
,先比较col_1
,再比较col_2
,以此类推。
参考:
在前面提到了一个疑问:
where a = 1 and b = 2 and c > 3 and d = 4
在已有联合索引(a, b, c, d)
时,c/d
可否用到联合索引?
在主要阅读的的2篇文章(美团大佬、java知音)都说的是:
最左前缀匹配原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就中止匹配。
好比a = 1 and b = 2 and c > 3 and d = 4 若是创建(a,b,c,d)顺序的索引,d是用不到索引的,
若是创建(a,b,d,c)的索引则均可以用到,a,b,d的顺序能够任意调整。
其中并未提到c
,并且我的以为 c&d 均可以用到索引(只是不知道其性能如何)。
针对这疑问,我看到了索引下推
。
例如以上SQL可能有2种执行可能:
1)假设 c&d 都没用到索引,根据联合索引查询到知足 a&b 的条件,而后就回表找到全部行数据,再进行遍历筛选出c > 3 and d = 4
的数据行。
2)假设 c&d 都用到了索引,那么最后回表的数据行 必定小于等于 1)
中回表的数据行,这就是mysql的索引下推
mysql默认启用索引下推,能够经过变量来修改:
SET optimizer_switch = 'index_condition_pushdown=off';
注意:
a) 索引下推只能用于二级索引。(聚簇索引包含了行数据,这时候索引下推并不会起到减小回表操做的效果)
b) 索引下推通常可用于所求查询字段(select列)不是/不全是联合索引的字段,查询条件为多条件查询且查询条件子句(where/order by)字段全是联合索引。(没理解~~)
备注:
我的并不肯定是 c&d 都用到索引,仍是只有 c 用到索引,d未用到索引。
(ps: cnblog的markdown对于 1.
和-
的解析貌似有错误,致使下面的序号是乱的)
索引不必定能提升查询速度,甚至可能比不存在索引时更慢!
一次查询只能用到1个索引
若是多列查询存在多个索引,查询优化器通常选择区分度高的索引列。
区分度,简单公式:count(distinct col) / count(*)。
意味着经过索引列能够返回更少的rows(回表查询的行数更少)
具体须要看实际数据,好比假设is_download只存在true/false,当下载完成后将false改成true。
此时实际业务数据是不多存在false,当存在大量查询false的时候,能够建立索引。
覆盖索引拥有更高效率和性能
<>
, !=
, not in
where phone=13800010002
(col_a, col_b)
的联合索引后,大多状况下不须要再建立a
索引基于 新增/修改索引 来优化查询时,不能只看到当前须要优化的SQL,还须要结合该表的其他查询SQL来综合分析。
例如,当前待优化sql建立了联合索引(col_1, col_2, col_3, col_4)
,可是可能另一条sql可能须要联合索引(col_1, col_2, col_4)
。因此,最终联合索引(col_1, col_2, col_4, col_3)
更适合。
联合索引,如何决定其col的顺序?
最左前匹配原则&列的区分度 的理解运用,固然还要结合实际SQL。
范围查询是否会使用索引(例如 like、between-and、in)?
可使用到索引(但具体仍是要看写法)。
性别字段是否须要建立索引(十万级以上的表,只有男/女)?
为何重复值高的字段不能建索引
mysql千万级大表,关于性别及年龄字段是否须要加索引?
没有绝对,要根据实际的数据。
例如1亿的数据,其中只有10万的"男"数据,而且老是查询少的那部分数据,那么存在索引的效果更好。
(ps:整理完一看,并无写或整理出多少东西...但磨磨唧唧也花费了蛮多时间)