索引是什么?
索引是帮助mysql高效获取数据的数据结构(有序)
优点:提高数据检索的效率,降低数据库的io成本,通过索引列对数据进行排序,降低排序的成本,降低cpu的消耗
缺点:索引列也是要占用空间的,索引大大提高了提高了查询效率,同时却也降低了更新表的速度
索引结构分类:
B+tree索引
Hash索引 通过hash表实现,只能实现精确匹配查询才有效,不支持范围查询
R-tree空间索引 空间索引是MYISAM的一种特殊索引类型,主要用于地理空间数据类型,通常使用较少
Full-text全文索引 是一种通过建立倒排索引,快速匹配文档的方式,类似于LUcene,SOlr,Es
b树:
b+树
为什么InnoDB存储引擎选择使用B+tree索引结构?
相对于二叉树,层级更少,搜索效率高
对于b树来说,无论是叶子节点还是非叶子节点,都会保留数据,这样导致一页中存储的键值减少,指针跟着减少,要同意保存大量数据,只能增加树的高度,导致性能降低
索引结构:
索引结构 | 描述 |
---|---|
B+Tree索引 | 最常见索引类型,大部分都支持 |
hash索引 | 底层用hash表实现的,不支持范围查询 |
R-tree | 空间索引是mylsam引擎的一个特殊索引类型,主要用于地理空间数据类型 |
full-text | 是一种倒排索引,快速匹配文档的方式 |
为什么选择使用B+tree索引结构?
相对于二叉树,层级更少,搜索效率高;
对于B-tree,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一页中存储的键值减少,指针跟着减少,要同样保存大量数据,只能增加树的高度,导致性能降低;
相对Hash索引l,B+tree支持范围匹配及排序操作;
索引分类:
- 主键索引:针对表中主键创建的索引,默认自动创建,只能有一个
- 唯一索引: 避免同一个表中某数据列中的值重复
- 常规索引: 快速定位特定数据
- 全文索引: 全文索引查找的是文本中的关键词,而不是比较索引中的值
在InnoDB下根据索引的存储形式,又可以分为以下两种:
- 聚集索引 将数据存储与索引放到一块,索引结构的叶子节点保存了行数据 (必须有,而且只能有一个)
选取规则:
如果存在主键,主键索引就是聚集索引,如果不存在,将使用第一个唯一索引作为聚集索引
如果表中没有主键或者合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引
- 二级索引 将数据和索引分开存储,索引结构的叶子节点关联的是对应的主键
索引语法
create (unique|fulltext) index index_name on table_name (index_col_name)创建索引
show index from table_name 查看索引
drop index index_name on table_name; 删除索引
sql性能分析:
show global status like 'Com_______' 7个下划线查看每种操作的次数
show variables like 'slow_query_log' 查看慢查询日志是否开启
show variables like 'slow_query_log_file'查看慢查询日志的位置
profile详情能够在做sql优化帮助我们了解
select @@have_profiling;查看是否支持
show profiles 查看每一条sql耗时的基本情况
show profile for query query_id 查看指定的query_id的sql语句各个阶段的耗时情况
show profile cpu for query query_id查看cpu的使用情况
直接在sql语句前面加上explain
id : select查询的序列号,表示查询中执行的select子句或者操作表的顺序(id相同,执行顺序从上到下,id不同值越大越先执行
select_type:表示select的类型,常见的取值有simple(简单表,即不使用表连接或者子查询),primary(主查询,即外层的查询),union(union中第二个或者后面的查询语句),subquery(select/where之后包含了子查询),derived包含在from子句中的子查询
type: 表示连接类型,性能由好到查的连接类型为NULL,system,const(主键或者唯一索引),eq_ref,ref(用非唯一性的索引),range,index,all
key: 实际使用的索引,如果为NULL,则没有使用索引
key_len:表示索引使用的字节数,该值为索引字段最大可能长度,并非实际使用长度,在不损失精确性的前提下,长度越短越好
row:mysql认为必须要执行查询的行数,在innodb引擎中是一个估计值,可能并不总是准确的
filtered:表示返回结果的行数,占需读取行数的百分比,filtered的值越大越好
extra:using index condition 查询使用了索引但是需要回表查询数据,using where ,using index 查询使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据
索引的使用:
最左前缀法则:
如果索引了多列(联合索引),要遵守最左前缀法则,最左前缀法则指的是查询从索引的最左列开始,并不跳过索引中的列
如果跳跃某一列,索引将部分失效(后面的字段索引失效)
注:mysql8之后优化器优化了最左前缀法则,可以进行跳跃,顺序也可以打乱
索引列运算:
不要在索引列进行运算操作,索引将失效
字符串不加引号:
字符串类型字段使用时,不加引号,索引将失效
模糊查询
如果仅仅是尾部模糊匹配,索引不会失效,如果是头部模糊匹配,索引失效
or连接的条件:
用or分割开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到
覆盖索引:
尽量使用覆盖索引(查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到),减少select *就是减少回表操作
前缀索引:
当前字段类型为字符串时,有时候需要索引很长的字符串,这会让索引变得很大,查询时,浪费大量的磁盘io,影响查询效率,
此时可以只将字符串的一部分前缀,建立索引,这样可以大大节约索引空间,从而提高索引效率
create index 名字 table名字(clomn(n))
索引下推
现在我们知道,对于联合索引(a, b),在执行 select * from table where a > 1 and b = 2
语句的时候,只有 a 字段能用到索引,那在联合索引的 B+Tree 找到第一个满足条件的主键值(ID 为 2)后,还需要判断其他条件是否满足(看 b 是否等于 2),那是在联合索引里判断?还是回主键索引去判断呢?
- 在 MySQL 5.6 之前,只能从 ID2 (主键值)开始一个个回表,到「主键索引」上找出数据行,再对比 b 字段值。
- 而 MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在联合索引遍历过程中,对联合索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。
当你的查询语句的执行计划里,出现了 Extra 为 Using index condition
,那么说明使用了索引下推的优化。
Sql提示:
如果有满足多个索引的话,mysql会使用列多的那个索引
use index()你用哪个索引
ignore index()你不用哪个索引
force index()你必须用这个索引
索引的设计原则
1.针对于数据量较大,且查询比较频繁的表建立索引。
2.针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引l。
3.尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。
4.如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。
5.尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。
6.要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率。
7.如果索引I列不能存储NULL值,请在创建表时使用NOTNULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确定哪个索引最有效地用于查询。