索引是什么?
索引是帮助MySQL高效获得数据的数据结构。
即:索引是一种数据结构。
可以理解为一种排好序的快速查找数据结构
索引的目的
目的是提高搜索效率,类似字典
索引的底层实现
- B Tree
- B+Tree
- full-text
- Hash
- R-Tree
一般默认为B树(多路查找树 + 链表)
索引适合的场景
多查询,少修改的场景
查询时:假如我们对数据库中的某一个字段建立了索引,我们下次需要对此字段进行查询时,直接从索引中,去查询,避免从无序的全表进行查询加快了查询速度
修改时:假如我们对数据库中的某一个字段建立了索引,我们下次需要对数据库进行修改时,我们在更改数据库中的真实数据的同时,还需要去修改对应的索引,使索引指向正确
索引分类
- 单值索引
对数据库表中的单个字段建立索引
-
唯一索引
建立的索引的字段是候选键(即:建立索引的字段的值在表中不重复)
-
复合索引
对数据库表中的多个字段建立索引
哪些情况需要建立索引?
1、 主键自动建立索引
2、 频繁作为查询条件的字段应该创立
3、 查询中与其他表关联的字段,外键应该建立索引
4、 频繁更新的字段不应该建立索引
5、 where条件中用不到的数据不应该建立索引
6、 单值索引与组合索引?优先创建组合索引
7、 查询中排序的字段
8、 查询中统计或者分组的字段
哪些情况不需要建立索引?
1、 经常增删改的表
2、 数据重复且分布平均的字段
如何分析SQL
1、 Explain + SQL语句
* ID: 优先执行ID大的字段,ID相同按顺序执行
* select\_type
* SIMPLE 简单的SQL查询
* PRIMARY 复杂查询的最外层为PRIMARY
* SUBQUERY 子查询
* DERIVED 衍生查询(临时表)
* UNION 联合查询的后面那一个SELECT
* UNION RESULT 对联合查询的结果进行SELECT
* table:表的来源
* type:查询类型,由最优到最差的排序有:
* system 表只有一行记录(系统表),这是const的特例,平时不会出现,忽略不计
* const 直接对主键或者Unique索引进行查询(唯一索引,主键自动建立唯一索引)
* eq\_ref (唯一性索引扫描)联表对主键或者Unique索引进行查询对于每个索引键,表中只有一条记录与之匹配
* ref (非唯一性索引扫描)返回匹配单独值的所有行,也是对索引进行扫描,但是索引值可能出现重复
* range 对索引进行范围性检索,在where语句中使用between、<、>、in等查询,这种扫描开始于索引某一点,结束于另一点,不用进行全局扫描
* index 扫描全部的索引树
* ALL 全表扫描
* possible\_keys 可能用到的索引
* key 实际使用的索引,若为NULL则没有使用
覆盖索引:possible\_keys中没有的,而key中出现
* key\_len 索引中使用的字节数,通过该列计算查询中使用的索引长度,在不丢失精度的情况下,越小越好,显示的是最大可能长度,而非是实际使用长度
* ref 显示索引上的值哪一列被使用了,如果可能的话,是一个常数。哪些列或常数被用于查找索引列上的值
* rows 每张表有多少行被优化器查询
* extra
* filesort 文件外排序,没有利用到索引去排序
* temporary 使用临时表排序,没有利用到索引
* index 表示相应的查询语句使用了覆盖索引(查询字段在该索引范围内,则该索引为覆盖索引),避免访问了表的数据行,效率高。(当索引被拿来进行执行索引的查找,则会多一个using where,没有using where则表示直接读取了索引的数据,没有进行查找)
索引失效案例与解决方案
case1: 单表范围查询导致复合索引失效
SQL语句:
SELECT * FROM table WHERE A = ? AND B > ? ORDER BY C ASC
假如我们建立了一个复合索引包含A、B、C三个字段,但是我们对第二个字段为范围查询,则会导致C字段不能使用索引进行排序,出现了filesort,使得SQL速度变慢
解决方法: 删除原来的索引,建立一个AC字段的索引,
case2: 索引两表连接优化
表连接的情况下
SELECT * FROM tb_A a LEFT JOIN tb_B b ON a.field = b.field
这类情况,应该给较少数据量的那一边建立索引,可以较好地提高效率。(即:给 tb_B 表建立索引)
左连接:给右边加索引
右连接:给左边加索引
case 3: 索引三表连接优化
SELECT * FROM tb_A a LEFT JOIN tb_B b ON a.field = b.field LEFT JOIN tb_C c ON b.field = c.field
这类情况可以把表分解拆分成两表的形式分析(给tb_B加索引,与给t b_C加索引)
case将持续更新……欢迎大家补充
JOIN优化
- 尽量减少nestedloop的循环次数(小表驱动大表
- 优先优化nestedloop的内层循环
- 保证被驱动表上的Join字段已经被索引
- 当无法保证被驱动表的Join字段被索引且内存充足的情况下,不要太吝啬JoinBuffer的设置