mysql 自动索引_MySQL索引总结

bb0aed0c01670831c3f90e364129c3bb.png

B+树索引和哈希索引的比较

大量唯一值的等值查询,哈希索引效率通常比B+tree高

hash索引不支持模糊查找

hash索引不支持联合索引中的最左匹配原则

hash索引不支持排序

hash索引不支持范围查询

hash索引只能显示应用于memory、NDB表

索引使用建议

1、经常检索的列;

2、经常用于表连接的列;

3、经常排序、分组的列;

索引不使用建议

1、基数很低的列;

2、更新频繁但检索不频繁的列;

3、BLOB、TEXT等长内容列;

4、很少用于检索的列;

数据库设计索引的原因

1、用于提升数据库的查找速度

2、提高聚合函数效率

3、提高排序效率,order by  asc、desc

4、有时可以避免回表

5、减少多表关联时扫描行数

6、列定义为default null 时,null值也会有索引,存放在索引数的最前端部分,因此尽量不要定义允许null

innodb索引类型

聚集索引

innodb表,只能够有一个,因为数据行在物理磁盘上只能有一份聚集存储。

innodb中,表即聚集索引,聚集索引即表

mysiam没有聚集索引的概念

聚集索引优先选择的列:

1、int/bigint

2、数据连续(单调)递增或自增

不建议的聚集索引:

1、修改频繁的列;

2、新增数据太过离散随机

不管innodb有没有主键,它都会有聚集索引,因为innodb是基于聚集索引的索引组织表

主键一定是聚集索引,聚集索引不一定是主键

主键索引

innodb的主键索引与行记录是存储在一起的,故叫做聚集索引

因为这个特性,innodb的表必须要有聚集索引:

(1)如果表定义了PK,则PK就是聚集索引;

(2)如果表没有定义PK,则第一个非空unique列是聚集索引;

(3)否则,InnoDB会创建一个隐藏的row-id作为聚集索引;

主键由表中的一个或多个字段组成,它的值用于唯一的标识表中的某一条记录

create table row_id(a int not null,b int null,c int not null,d int not null,unique key(b),unique key(d),unique key(c));

insert into row_id select 1,2,3,4;

insert into row_id select 5,6,7,8

insert into row_id select 9,10,11,12;

select a,b,c,d,_rowid from row_id;

另外_rowid只能查看单列为主键的情况,对于多列组成的主键就显得无能为力了

作用:

1、保证数据的完整性;

2、加快数据的操作速度;

3、主键值不能重复,也不能包含null;

主键选择建议:

对业务无意义,不必受限于业务变化的影响;

很少修改和删除;一般都是自增的

不建议使用较长的列做主键,例如char(64),因为所有的普通索引都会存储主键,会导致普通索引过于庞大;

建议使用趋势递增的key做主键,由于数据行与索引一体,这样不至于插入记录时,有大量索引分裂,行记录移动;

例如:select * from t where name='lisi';

会先通过name辅助索引定位到B+树的叶子节点得到id=5,再通过聚集索引定位到行记录。所以,其实扫了2遍索引树。

53a986843320765bb905e91c6602a0bf.png

innodb主键特点:

定义索引时,不管有无显示包含主键,实际都会存储主键值;

在MySQL5.6.9版本后,优化器已能自动识别索引末尾的主键值,之前版本则需要显示加上主键列才可以被识别(经过测试,老版本也支持此特征)

例如:

911af9db432c688c6f3b31205df620f2.png

ebb128a2534361c3bca33ee6b82470f7.png

仍然遵循最左前缀原则:

898f675fb392b0ee77f252e24df7ba19.png

034259380238eccc80d25fb6956c009f.png

唯一索引

不允许具有索引值相同的行,从而禁止重复的索引或键值(在唯一约束上,和主键一样)

唯一索引允许有空值(NULL);

一个表只能有一个主键,但可以有多个唯一索引;

innodb表中主键必须是唯一索引,但唯一索引不一定是主键;

联合索引

多列组成的索引

适合where条件中的多列组合

可以避免回表(覆盖索引)

支持多列不同的排序规则(8.0开始支持倒序索引)

联合索引建议:

where条件中,经常同时出现的列放在联合索引中;

把选择性大的列放在联合索引最左边

覆盖索引

通过索引数据结构即可完成查询返回数据,不需要回表

执行计划中,Extra为关键字 using index;

desc select name from t1 where name like '%zyq%';

0e461caba5eafb2c9563a77e8d23d5a2.png

前缀索引

使用的原因:

char、varcahr列太长,全部创建索引的话,效率太差,存在浪费;

或者blob、text类型不能整列作为索引列,因此需要使用前缀索引

部分索引选择建议:

1、统计平均值;

10273ff5f520513da6f7e3dc58562fd6.png

2、满足10%-30%的覆盖度就可以

缺点:

无法利用前缀索引完成排序

03da44b74d2f8614b1b7ddda64a882f8.png

d8a1fd6beb19a052f7432aa36b6da13d.png

与全部索引对比:

9591eb10eb64741126cfa080fc76ba59.png

全文索引

5.6之前,全文索引支持mysiam引擎,5.6以后也支持innodb引擎

索引长度

索引的最大长度767bytes

启用innodb_lagrge_prefix,增加到3072bytes,只针对dynamic,compressed格式管用

对于redundant、compact格式,最大索引长度还是767bytes

mysiam表索引最大长度是1000bytes

最大排序长度默认是1024(max_sort_length)

索引管理

创建删除索引

alter table  t  add index idx(c1) using btree;

create index idx_name on t(c1) using btree;

create table 表时也可以顺便创建索引;

alter  table t drop index idx_name;

drop index idx_name on t;

MySQL各版本,对于add Index的处理方式是不同的,主要有三种:

Copy Table方式

这是InnoDB最早支持的创建索引的方式。创建索引是通过临时表拷贝的方式实现的。

1. 新建一个带有新索引的临时表。

2. 然后锁原表,禁止DML操作,允许读操作。

3. 将原表数据全部拷贝到临时表(无排序,一行行拷贝)。

4. 然后Rename,升级字典锁,禁止读写。

5. 完成创建索引的操作。

这种copy方式的效率没有inplace好 ,因为copy需要记录undo和redo log,而且因为临时占用buffer pool引起短时间内性能受影响。

Inplace方式

这是原生MySQL 5.5,以及innodb_plugin中提供的创建索引的方式。所谓Inplace,也就是索引创建在原表上直接进行,不会拷贝临时表。

1. 新建一个带有新索引的临时表。

2. 然后锁原表,禁止DML操作,允许读操作。

3. 读取聚集索引,构造新的索引项,排序并插入新索引。

4. 然后Rename,升级字典锁,禁止读写。

5. 完成创建索引的操作。

可以避免重建表带来的IO和CPU消耗,保证DDL期间依然有良好的性能和并发。

Inplace方式创建索引,创建过程中,原表同样可读的,但是不可写。

Online方式

这是MySQL5.6.7中提供的创建索引的方式。无论是CopyTable方式,还是Inplace方式,创建索引的过程中,原表只能允许读取,不可写。

对应用有较大的限制,因此MySQL最新版本中,InnoDB支持了所谓的Online方式创建索引。

InnoDB的Online Add Index,首先是Inplace方式创建索引,无需使用临时表。在遍历聚簇索引,收集记录并插入到新索引的过程中,原表记录可修改。而修改的记录保存在Row Log中。当聚簇索引遍历完毕,并全部插入到新索引之后,重放Row Log中的记录修改,使得新索引与聚簇索引记录达到一致状态。

与Copy Table方式相比,Online Add Index采用的是Inplace方式,无需Copy Table,减少了空间开销;与此同时,Online Add Index只有在重放Row Log最后一个Block时锁表,减少了锁表的时间。

与Inplace方式相比,Online Add Index吸收了Inplace方式的优势,却减少了锁表的时间。

help create index;

CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name

[index_type]

ON tbl_name (index_col_name,...)

[index_option]

[algorithm_option | lock_option] ...

index_col_name:

col_name [(length)] [ASC | DESC]

index_option:

KEY_BLOCK_SIZE [=] value

| index_type

| WITH PARSER parser_name

| COMMENT 'string'

index_type:

USING {BTREE | HASH}

create index idx_c on sbtest1(c(20)) ALGORITHM=DEFAULT;

create index idx_c on sbtest1(c(20)) ALGORITHM=INPLACE;

写不会阻塞,会先写到缓存,然后完成之后同步数据;

copy的时候会阻塞写操作

create index idx_c on sbtest1(c(20)) ALGORITHM=COPY;

innodb_online_alter_log_max_size

如果DDL执行时间很长,期间又产生了大量的dml操作,以至于超过了innodb_online_alter_log_max_size变量所指定的大小,会引起DB_ONLINE_LOG_TOO_BIG错误。默认为128M,特别对于需要拷贝大表的alter操作,考虑临时加大该值,以此获得更大的日志缓存空间。

9cc843f07c19b15acc3f280f3302066c.png

指定InnoDB表的联机DDL操作期间使用的临时日志文件大小的上限(以字节为单位)。每个正在创建的索引或要更改的表都有一个这样的日志文件。此日志文件存储在DDL操作期间在表中插入,更新或删除的数据。临时日志文件在需要时由innodb_sort_buffer_size的值扩展,最大为innodb_online_alter_log_max_size指定的最大值。如果临时日志文件超出大小上限,则ALTER TABLE操作将失败,并且将回滚所有未提交的并发DML操作。因此,此选项的较大值允许在联机DDL操作期间发生更多DML,但在表被锁定以应用日志中的数据时,还会延长DDL操作结束时的时间段。

冗余索引

根据最左匹配原则,一个索引是另一个索引的子集;

使用pt-duplicate-key-checker检查

select * from sys.schema_redundant_indexes;

无用索引:

几乎从未被使用过的索引

pt-index-usage检查低利用率索引,提供删除建议

select * from sys.schema_unused_indexes;

全表扫描

select * from sys.schema_tables_with_full_table_scans;

使用索引

1、让MySQL自动选择

select ... from  t where ...

2、建议选择:

select .. from t  use index(idx_name) where ...

3、强制索引

select ...  from t force index(idex_name) where...

索引统计

表统计信息

show table status ;

select * from information_schema.tables;

select * from mysql.innodb_table_stats;

索引统计信息

show index from  table;

select * from information_schema.STATISTICS;

select * from mysql.innodb_index_stats;

27a90ffd893b866ed9f268fce5471dae.png

innodb_stats_auto_recalc

默认开启,当修改数据量大于10%,自动更新统计信息;

innodb_stats_persistent

默认开启,统计信息持久化存储;当关闭时,统计信息不持久化,每次动态采集,存储在内存中,重启实例(需要重新统计),不推荐

innodb_stats_persistent_sample_pages

统计信息持久化存储时,默认每次采集20个page页

innodb_stats_on_metadata

默认禁用,访问元数据时更新统计信息;

iinnodb_stats_transient_sample_pages

动态采集page,默认8个

MySQL -A登录不会去更新统计信息

不接-A的话当表或者分区表比较多的时候登录会比较慢

use database是也需要更新统计信息,所以有时候很慢

执行计划

type

ALL 扫描全表数据

index 遍历索引

range 索引范围查找

ref 使用非唯一索引查找数据

fulltext 使用全文索引

const 使用主键或者唯一索引,且匹配的结果只有一条记录。

system const 连接类型的特例,查询的表为系统表。

possible_keys

可能使用的索引,但不一定会使用。查询涉及到的字段上若存在索引,则该索引将被列出来。当该列为NULL时就需考虑当前的SQL是否需要优化。

key

显示MySQL在查询中实际使用的索引,若没有使用索引,显示为NULL。

查询中若使用了覆盖索引(覆盖索引:索引的数据覆盖了需要查询的所有数据),则该索引仅出现在key列表中

extra

extra的信息非常丰富,常见的有: 1.Using index 使用覆盖索引 2.Using where 使用了用where子句来过滤结果集 3.Using filesort 使用文件排序,使用非索引列进行排序时出现,非常消耗性能,尽量优化。 4.Using temporary 使用了临时表

索引不可用的情况

1、通过索引扫描的记录数超过20%-30%,可能会变成全表扫描;

2、联合索引中,第一个索引列使用范围查询;(这时用的部分索引)

3、联合索引中,第一个查询不是最左索引列;

4、模糊查询条件列最左以通配符%开始(覆盖索引除外);

5、两个独立索引,其中一个用于检索,一个用于排序(只能用到一个索引)

6、join查询时,关联列数据类型(以及字符集)不一致也会导致索引不可用

隐式类型转换

u1='123' 不会转换

u1='a' 可以正常走索引

联合索引

c0e7f94b9ebd4a4890929553ff568ffb.png

desc select * from t7 where name='zyq';

desc select * from t7 where c='abc';

d958f419a674921751dbc31eb4583f30.png

b27444f4049f8dee39e16a5ed694b84d.png

desc select * from t7 where c='zyq' and pad='sdfafadfasfdaf';

153e9da566daaea7ba096d8c591e5dc8.png

desc select * from t7 where c='abc' and name='zyq';

2db521e1f5addf745f93b35c7191731a.png

db7da4520aee5bac4f8c287f158d2377.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值