MySQL索引基础篇

MySQL索引

索引是什么?

索引是帮助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的设置

你可能感兴趣的:(数据库)