MySQL索引最佳实践

MySQL最佳索引实践

索引的作用

加速数据库访问
增强数据约束性(UNIQUE, FORREIGN KEY)

索引类型

BTREE
HASH
FULLTEXT

MyISAM 与 InnoDB索引区别

  • MyISAM数据指针直接指向数据文件的物理偏移位置
  • InnoDB的数据存储在主键索引的叶子节点上,次要索引(Secendary) 存储指向主键索引的指针

Btree 索引适合哪些操作

  • KEY = 6 (查询)
  • KEY >6 (开区间)
  • 5 < KEY <10 (闭区间)

字符索引

  • 'AAA' < 'BBB',与其他比较相同
  • 前缀索引 'abc%'
  • '%sdf' 不可以使用索引优化查询

复合索引

  • KEY (col1, col2, col3)
  • 注意复合索引使用的顺序

    低效的索引

  • 长的Innodb主键索引
  • Innodb随机主键索引
  • 低选择性的索引

InnoDB 索引

  • 数据由主键聚合
  • 主键索引总是附加到所有的索引中

MySQL使用索引的地方

  • 数据查询
  • 数据排序
  • 避免从表中读取数据

数据查询中使用索引

  • 普通查询 SELECT * FROM EMPLOYEES WHERE LAST_NAME=“Smith”
  • 复合索引 SELECT * FROM EMPLOYEES WHERE LAST_NAME=“Smith” AND DEPT=“Accounting” 使用 索引 (LAST_NAME, DEPT)

复合索引的注意事项

index(A, B, C)
可用索引的查询

  • A>5
  • A=5 AND B>6
  • A=5 AND B=6 AND C=7
  • A=5 AND B IN (2,3) AND C>5
    不会使用索引:
  • B > 5
  • B = 6 AND C=7
    部分使用索引
  • A >5 AND B=2
  • A =5 AND B >6 AND C =2

    总结: 在使用复合索引时,当碰上范围查询(<.>,BETWEEN), 使用IN不受影响

使用索引排序

  • SELECT * FROM PLAYERS ORDER BY SCORE DESC LIMIT 10
    将使用 SCORE 列的索引,无索引的话会使用低效的 filesort
  • SELECT * FROM PLAYERS WHERE COUNTRY=“US”ORDER BY SCORE DESC LIMIT 10
    可使用复合索引(CONTRY, SCORE)

复合索引高效排序

KEY(A, B)
使用索引的情况:

  • ORDER BY A #首列排序
  • A =5 ORDER BY B #首列相等,此列排序
  • ORDER BY A DESC, B DESC #相同排序方向
  • A>5 ORDER BY A #范围查询和排序在同一列
    不会使用索引:
  • ORDER BY B #
  • A>5 ORDER BY B
  • A IN(1,2,3) ORDER BY B
    -ORDER BY A ASC, B DESC

规则:

  • 两列排序方向必须一致
  • ORDER BY 之外的列必须使用等于条件,不可以用IN

避免读取数据

覆盖索引: 并不是一种索引,而是直接从索引中返回查询数据,无需从表中获取。
SELECT STATUS FROM ORDERS WHERE CUSTOMER_ID=123
– KEY(CUSTOMER_ID,STATUS)

Min/Max 优化

再聚合函数 min,max,group 中,可以对聚合的字段进行索引

联合查询 索引

MySQL的关联查询是嵌套循环的方式查找数据的。对Join的字段进行索引能极大地提高查询效率。
仅需在被查询的表上对应的字段建立索引

索引合并

mysql可以在一次查询中使用多个索引,这就是索引合并(index merge), 此时使用联合索引会更好

前缀索引

使用前缀索引只是对BOLB/TEXT字段的部分数据建立索引,会减少索引的体积,但是不能作为覆盖索引使用
ALTER TABLE TITLE ADD KEY(TITLE(20));
注意前缀索引的索引长度的问题,选择唯一性最大的长度。

select count(distinct(title)) total, 
count(distinct(left(title,10))) p10, 
count(distinct(left(title,20))) p20 from title;

MySQL 如何选择使用索引

  • 每条SQL的动态查询性能
  • 估算需要访问的数据的行数
  • 索引基数 Cardinality,该值由 ANALYZE TABLE 更新
  • 判断是否全表扫描会更快或相等
  • 是否使用索引排序

使用EXPLAIN

Explain 可以查看MySQL如何计划执行该SQL

  • type: 从好到坏排序 system,const,eq_ref, ref, range, index, ALL
  • rows: 大概需要扫描的行数,数量越大意味着查询更慢
  • key-len: 显示有多少key被使用
  • Extra: Using Index 使用索引,Using Filesort 使用排序, Using Temporary 使用临时表

使用索引的策略

  • 针对性能影响严重的查询建立索引,从综合方面考虑
  • 如果所有的WHERE 条件和JOIN条件可以在查询中使用索引就更好了
  • 在优化是综合考虑性能影响
  • 通用的扩展索引而不是一直创建索引

索引实践

SELECT * FROM TBL WHERE A=5 AND B=6
SELECT * FROM TBL WHERE A>5 AND B=6

根据以上两个查询,使用KEY(B,A) 的索引更好
不要对无性能问题的查询添加索引
过多的索引不仅占用空间,而且影响速度

枚举类型

KEY(A, B)
SELECT * FROM TBL WHERE A BETWEEN 2 AND 4 AND B=5 会使用索引
SELECT * FROM TBL WHERE A IN (2,3,4) AND B=5 不会使用索引

添加条件过滤

KEY(GENDER,CITY)
SELECT * FROM PEOPLE WHERE CITY=“NEW YORK” 不会使用索引
SELECT * FROM PEOPLE WHERE GENDER IN ("M","F") AND CITY=“NEW YORK” 可使用索引
技巧:在低选择性的列中可以这样使用,比如性别(gender),状态(status),布尔值等

联合查询排序

KEY(A,B)
SELECT * FROM TBL WHERE A IN (1,2) ORDER BY B LIMIT 5 不会用到索引
(SELECT * FROM TBL WHERE A=1 ORDER BY B LIMIT 5) UNION ALL (SELECT * FROM TBL WHERE A=2 ORDER BY B LIMIT 5) ORDER BY B LIMIT 5; 会在排序中用到索引,仅需对联合的结果做排序

你可能感兴趣的:(mysql,索引优化)