MySql索引以及优化-日常充电
Posted JF Coder
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySql索引以及优化-日常充电相关的知识,希望对你有一定的参考价值。
索引是帮助MySql高效获取数据的排好序的数据结构
索引的数据结构
二叉树,红黑树,Hash表,B-Tree
创建索引
ALTER TABLE用来创建普通索引、UNIQUE索引或PRIMARY KEY索引。
ALTER TABLE table_name ADD INDEX index_name (column_list)
ALTER TABLE table_name ADD UNIQUE (column_list)
ALTER TABLE table_name ADD PRIMARY KEY (column_list)
CREATE INDEX可对表增加普通索引或UNIQUE索引。
CREATE INDEX index_name ON table_name (column_list)
CREATE UNIQUE INDEX index_name ON table_name (column_list)
其中table_name是要增加索引的表名,column_list指出对哪些列进行索引;另外,不能用CREATE INDEX语句创建PRIMARY KEY索引。
删除索引
可利用ALTER TABLE或DROP INDEX语句来删除索引。类似于CREATE INDEX语句,DROP INDEX可以在ALTER TABLE内部作为一条语句处理,语法如下。
DROP INDEX index_name ON talbe_name
ALTER TABLE table_name DROP INDEX index_name
ALTER TABLE table_name DROP PRIMARY KEY
索引存储方式
- B+Tree(mysql默认索引存储数据结构)
- Hash
对索引的key进行一次hash计算就可以定位出数据存储的位置
很多时候Hash索引要比B+Tree索引高效
仅满足“=”,“IN”,不支持范围查询
hash冲突问题
如图Hash的算法:value % 13 = index
- 扩展B树(注意和B+Tree的区别)
MyISAM和InnoDB实现BTree索引方式的区别
MyISAM存储引擎索引实现
B+Tree叶节点的data域存放的是数据记录的地址。在索引检索的时候,首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其 data 域的值,然后以 data 域的值为地址读取相应的数据记录。这被称为“非聚簇索引”。
MyISAM索引文件和数据文件是分离的 ;如图:myisam表文件
InnoDB存储引擎索引实现
其数据文件本身就是索引文件。相比MyISAM,索引文件和数据文件是分离的,其表数据文件本身就是按B+Tree组织的一个索引结构,树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。这被称为“聚簇索引(或聚集索引)”
InnoDB表数据文件本身就是主索引 如图:innodb表文件
聚集索引的优点
聚集索引查找的速度非常的快,因为整个B+树本身就是的多叉平衡树,叶子节点是有序的,所以找到了索引就等于是找到了相应的数据
聚集索引的缺点
依赖于有序的数据。B+树本身就是多叉平衡树,如果索引的数据不是有序的,那么就需要在插入的时候进行排序,如果数据是整刑还比较好操作,如果是字符串或者是uuid这种又长又难比较的数据,插入和查找的速度肯定就很慢了
更新代价比较大。如果索引列的数据被修改,那么相应的索引也要修改,加上聚集索引的叶子节点上还存放了数据,修改的代价就更大了。所以对于主键索引来说,一般主键是不允许修改的。
为什么建议InnoDB的表要建议设置主键,并且推荐使用整型的自增主键? 如果没有设置主键,InnoDB会选择一个不包含null值的唯一索引作为主键索引;如果没有选到唯一值的索引列,mysql会帮忙建立一个隐藏列,维护一个唯一id,以此来组织索引,那么为了避免 mysql选择索引列和建立隐藏列的性能损耗,建议手动建立一个主键。
索引分类
- 单值(普通)索引:即一个索引只包含单个列,一个表可以有多个单值索引;NORMAL
- 唯一索引:索引列的值必须唯一,单允许空值;UNIQUE
- 全文索引:表示全文收索,在检索长文本的时候,效果最好;FULLTEXT
- 空间索引:MYSQL使用SPATIAL关键字进行扩展,使得能够用于创建正规索引类型的语法创建空间索引。创建空间索引的列,必须将其声明为NOT NULL,空间索引只能在存储引擎为MYISAM的表中创建;
建议需要创建索引
- 主键自动建立唯一索引(设置表的主键就自动创建索引)
- 频繁作为查询条件的字段应该创建索引
- 查询中与其它表关联的字段,外键关系建立索引
- 频繁更新的字段不适合创建索引,因为每次更新记录还会更新索引
- where条件里用不到的字段不创建索引
- 单键/组合索引的选择(高并发下倾向创建组合索引)
- 查询中排序的字段,排序字段若通过索引访问将提高排序速度
- 查询中统计或者分组字段(orderby 分组前要排序)
不建议创建索引
- 表记录太少
- 经常增删改的表
- 某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果
性能分析
用EXPLAIN关键字,来查看索引是否正在被使用,并且输出其使用的索引信息
**id:**为SELECT的识别符。这是SELECT的查询序列号,如果是子查询,id序号会递增,id的值越大优先级越高。
**select_type:**表示使用SELECT的查询类型,SIMPLE表示为简单的SELECT,不适用于UNION或子查询,就是简单的SELECT。也就是说该SELECT查询时会使用索引。其他取值:**PRIMARY:**最外面的SELECT,在有子查询时,就会出现两个以上的SELECT。
**UNION:**union(两张表连接)中的第二个或后面的select语句。
**SUBQUERY:**在子查询中,第二个SELECT。
**table:**数据表的名字。按照被读取的先后顺序排列,这里只查询一张表,所以只显示book。
**type:**显示的是访问类型,是较为重要的指标,结果值从好到坏(一般大于range就差不多了)system(系统表)>const>eq_ref>ref>range>index>All。
Type | 访问类型 system(系统表)>const>eq_ref>ref>range>index>All |
---|---|
const | 表示通过索引一次就找到了,const用于比较primary key或者unique索引 |
eq_ref | 唯一索引扫描,表中一条记录与之匹配 |
ref | 非唯一索引扫描,返回匹配某个单独值的所有行 |
range | 只检索给定范围的行,使用一个索引来选择行,比index强 |
index | index和All都是读全表,但是index是从索引中读取的,而All是从硬盘中读取的 |
建议: | 最好达到range以上,可做sql优化达到 |
**possible_keys:**显示可能应用在这张表中的索引,一个或者多个。
**key:**实际选用的索引,如果为null则没有使用索引。
key_len:显示了mysql使用索引的长度(也就是使用的索引个数),长度越短越好。注意,key_len的值可以告诉你在联合索引中mysql会真正使用了哪些索引。
ref:用于连接程序使用键的最左前缀或者是该键不是 primary key 或 unique索引;可能的取值有 system、const、eq_ref、index和All。
**rows:**根据表统计信息及索引引用情况,大致估算出找到所需的记录所需要读取的行数。
**extra:**提供了与关联操作有关的信息,没有则什么都不写。
extra | 提供了与关联操作有关的信息 |
---|---|
Using filesort | 说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行,Mysql无法利用索引完成的排序操作称为“文件排序” |
Using temporary | 使用了临时表保存中间结果,Mysql在对查询结果排序时使用临时表,常见于排序orderby和分组查询groupby,union等; |
Using index | 表示相应的select操作使用了覆盖索引(Covering Index),避免访问表的数据行,如果同时出现using where,表明索引被用来执行索引键值的查找;如果没有出现using where,表明索引用来读取数据而非执行查找动作; |
Using where | 表示使用了where查询 |
using join buffer | 使用了连接缓存 (使用join多了,配置文件的join buffer可以调大) |
impossible where | where子句的值总是false,不能用来获取元组 |
覆盖索引(Covering Index):索引是可以高效找到行的方法,但是一般数据库也能使用索引找到一个列的数据,因此不必读取整个行;毕竟索引叶子节点(BTree)存储了要索引的数据,当能通过读取索引就可以拿到数据,就不需要读取行了,一个索引包含(覆盖)了满足查询结果的数据就叫做覆盖索引;可以减少回表查询;
案例分析
待完善
以上是关于MySql索引以及优化-日常充电的主要内容,如果未能解决你的问题,请参考以下文章