1.索引
1.1.定义
MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。
我们平常所说的索引,如何没有特别的指明,都是B树(多路搜索树,并不一定是二叉的)结构组织索引,其中聚集索引,次要索引,覆盖索引,复合索引,前缀索引,唯一索引默认都是使用B+树索引,统称索引,当然除了B+数这种类型的索引外还有(hash索引等)
1.2.优劣势
索引
优势:
类似大学图书馆建书目索引,提高数据检索的效率,降低数据IO成本
通过索引列对数据排序,降低数据排序的成本,降低CPU的消耗
劣势:
实际上索引也是一张表,该表保存了主键和索引字段,并指向实体表的记录,所以索引也是要占空间的
虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅 要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息
索引只是提高效率的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询
1.3.索引分类
单值索引:一个索引只包含单个列,一个表可以有多个单列索引
唯一索引:索引列的值必须唯一,但允许有空值
复合索引:一个索引包含多个列
基本语法:
创建:
CREATE [UNIQUE] INDEX indexName ON mytable(columnname(length)) ALTER mytable add[unique] index [indexname] on (columnname(length))
删除:
DROP INDEX[INDEXNAME] ON Mytable
查看:
show index from table_name\G
使用ALTER命令:
ALTER TABLE tbl_name ADD PRIMARY KEY (column_list) #该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL ALTER TABLE tbl_name ADD UNIQUE index_name (column_list) #这条语句创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次) ALTER TABLE tbl_name ADD INDEX index_name (column_list) #添加普通索引,索引值可出现多次 ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list) #该语句指定了索引为FULLTEXT,用于全文索引
1.4.索引使用场景
哪些情况需要创建索引:
1.主键自动建立唯一索引;
2.频繁作为查询条件的字段应该创建索引;
3.查询中与其它表关联的字段,外键关系建立索引;
4.频繁更新的字段不适合创建索引-因为每次更新不单单是更新了记录还会更新索引;
5. Where条件里用不到的字段不创建索引;
6.单键/组合索引的选择问题,who? (在高并发下倾向创建组合索引);
7.查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度;
8.查询中统计或者分组字段
哪些情况不要创建索引:
1.表记录太少;
2.经常增删改的表;
3.数据重复且分布平均的表字段,应该只为最经常查询和最经常排序的数据列建立索引。
注意,如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果。
(比如一个表有10万行记录,有一个字段A只有T和F两种值,且每个值的分布概率大约为50%,那么对这种表A字段建立索引一般不会提高数据库的查询速度。
索引的选择性是指索引列中不同值的数目与表中记录数的比。如果一个表中有2000条记录,表索引列有1980个不同的值,那么这个索引的选择性就是1980/2000=0.99。
一个索引的选择性越接近于1,这个索引的效率就越高。)
2.Explain性能分析
使用Explain关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句,分析你的查询语句或是表结构的性能瓶颈。
具体分析结果包含:表的读取顺序、数据的读取操作的操作类型、哪些索引可以使用、哪些索引被实际使用、表之间的引用、每张表有多少行被优化器查询
2.1.id(执行顺序)
explain + sql 执行之后会显示如下信息列,表示mysql执行当前sql的执行信息。
id:select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
id显示的执行顺序一共有三种情况:
①id相同,执行顺序由上至下;
②id不同,如果是子查询,id序号会递增,id值越大优先级越高,越优先被执行
③id相同与不同,同时存在
2.2.select_type(查询类型)
select_type:表示查询的类型,主要是用于区别该条sql语句是普通查询、联合查询、子查询等的复杂查询
select_type的类型有以下几种:
SIMPLE:简单的select查询,查询中不包含子查询或者union;
PRIMARY:查询中若包含任何复杂的子部分,最外层则被标记为;
SUBQUERY:在select或where列表中包含子查询;
DERIVED:在FROM列表中包含子查询被标记为DERIVED (衍生) MYSQL会递归执行这些子查询,把结果放在临时表中
UNION:若第二个SELECT出现在UNION之后,则被标记为UNION,若UNION包含在FROM子句的子查询中,外层SELECT将被标记为DERIVED
UNION RESULT:从UNION表获取结果的SELECT
2.3.Table
table用于显示这一行数据是来自哪一张表的
2.4.Type
type显示的是访问类型,是较为重要的一个指标,主要的类型有:
一般在实际开发中,结果值从最好到最坏依次是:
system > const > eq_ref > ref > range > index > ALL
一般来说,sql优化得保证查询至少达到range级别,最好能达到ref。
system:表中只有一行记录(等于系统表),这是const类型的特例,平时不会出现,这个也可以忽略不计;
const:表示通过索引一次就找到了,const用于比较primary key 或者unique索引,因为只匹配一行数据,所以很快将主键置于where列表中,MySQL就能将该查询转换为一个常量
eq_ref:唯一索引扫描,对每个索引键,表中只有一条记录与之匹配,常见于主键或唯一索引扫描
ref:非唯一性索引扫描,返回匹配的某个单独值所有行,本质上也是一种索引访问,
它返回所有匹配单个单独值的行,然而他可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体
range:只检索给定范围的行,使用一个索引来选择行,key列显示使用了哪个索引,一般就是在where语句中出现了between、<>、in等查询,这种范围扫描比
全表扫描要好,因为它开始于索引的某一点而结束于另一点,不用扫描全部索引
index:index与ALL区别为index类型值遍历索引,通常比ALL快,因为索引文件通常比数据文件小
(all和index都是读全表,但index是从索引中读取的,而all是从硬盘中读的)
all:全表扫描,将遍历全表以找到匹配的行
2.5.possible_keys/key
possible_keys:显示可能应用在这张表中的索引,一个或多个查询设计到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用
key:实际使用的索引,如果为NULL,则没有使用索引
注意:查询中若使用了覆盖索引,则该索引仅出现在key列表中
2.6.key_len
key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引长度,在不损失精确性的情况下,长度越短越好
key_len显示的值为索引字段的最大可能长度,并非实际使用长度,及key_len是根据表定义计算而得,而不是通过表内检索出的
原则:同一检索条件下,key_len长度越短越好,消耗小、性能高。
2.7.ref
ref:显示索引的那一列被使用了,如果可能的话,是一个常数,那些列或常量被用于查找所有列上的值
2.8.rows
rows:根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要的读取行数
2.9.Extra
extra:包含不适合在其它列中显示但十分重要的额外信息,主要类型有:
Using filesort:说明mysql会对数据使用一个外部索引排序,而不是按照表内的索引顺序进行读取,MySQL中无法利用索引完成的排序操作称为“文件排序” (性能较差)
Using temporary:使用临时表保存了中间结果,MySQL在对查询结果排序时时使用临时表,常见于排序order by 和分组查询group by (性能最差)
Using index:表示相应的select操作中使用了覆盖索引(Covering Index) 避免访问了表的数据行,效率不错,如果同时出现using where 表明索引被用来执行索引键值的查找。如果没有出现using where 表明该索引用来读取数据而非执行查找动作 (性能不错)
覆盖索引:又名索引覆盖,就是select的数据列只用从索引中就能获取,不必读取数据行,MySQL可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件,换句话说查询列要被所建的索引覆盖。
简单理解覆盖索引:及所查询字段与所建立的索引在个数、顺序上一致,或者包含在索引查询范围内(个数小于、顺序包含)。
注意:如果要使用覆盖索引,一定要注意select列表中只取出需要的列,不可select *,因为如果将所有字段一起做索引会导致文件过大,查询性能下降。
Using where:表示where连接
Using join buffer:表示使用了连接缓存