MySql索引

索引的定义
  MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构.可以得出索引的本质就是数据结构
  你可以简单理解为"排序好的快速查找数据结构"
  在数据之外,数据库还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构的基础上实现高级查找算法,这种数据结构就是索引
  一般来说索引本身很大,不适合全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上
  我们平常所说的索引,如果没有特别指明,都是指B树(多路搜索树,并不一定是二叉的)结构组织的索引,其中聚集索引,次要索引,覆盖索引
  复合索引,前缀索引,唯一索引默认都是使用B+树索引,统称索引.当然,除了B+树这种类型的索引之外,还有哈稀索引(hash index)等

优势
  类似大学图书馆建书目录索引,提高数据检索的效率,降低数据库的IO成本
  通过索引列对数据进行排序,降低数据排序成本,降低了CPU的消耗
  可以加速表和表之间的连接
劣势
  实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引也是要占内存空间的
  虽然索引大大提高了查询速度,同时都会降低更新表的速度,如对表进行insert,update和delete
  因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件每次更新添加了索引的字段,都会调整因为更新所带来的键值变化后的索引信息
  索引只是高效的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询方法

索引的分类
  单值索引:即一个索引只包含单个列,一个表不\可以有多个单列索引
  唯一索引:索引列的值必须唯一,但允许有控制,例如手机号,银行卡号等值必须是唯一
  复合索引:即一个索引包含多个列,例如手机号和银行卡号一起,如果一个表中的数据在查询时有多个字段总是同时出现则这些字段就可以作为复合索引
基本语法
  创建:create [unique] index indexName on tbname(columnname(lenght))
  更改:alter table tbname add [unique] index [indexName] on (columnname(lenght))
  更改:alter table tbname add [unique] fulltext [indexName] on (columnname(lenght))#指定索引为fulltext,用于全文索引
  删除:drop index [indexName] on tbname;
  查看:show index from tbname\G;

索引结构
  BTree索引
  Hash索引
  full-text全文索引
  R-Tree索引


哪种情况需要创建索引
  1.主键自动建立唯一索引
  2.频繁作为查询条件的字段应该创建索引
  3.查询中与其他表关联的字段,外键关系建立索引
  4.频繁更新的字段不适合创建索引,因为每次更新不单单是更新数据还会更新索引
  5.Where条件里用得到的字段适合创建索引
  6.单键/组合索引的选择问题,在高并发下倾向创建组合索引
  7.查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
  8.查询中统计或者分组字段
哪种情况不需要建索引
  1.表记录太少(一般生产环境下,三百万条记录性能就可能开始下降,官方说的是五百万到八百万)
  2.经常增删改的表
  3.某个数据列的值包含许多重复的内容

导致索引失效的案例
  1.建什么索引用什么索引,顺序也最好保持一致
  2.最佳左前缀索引名称命名(如字段name,age,city,则索引命名应该是nameAgeCity或者xxx_nameAgeCity,顺序很重要)
  3.不在索引列上做任何操作(计算,函数,or,类型转换),会导致索引失效而转向全表扫描
  4.存储引擎不能使用索引中范围条件右边的列(如name='lin' and age>25 and city='qingdao',则age后面的索引会实效)
  5.尽量使用覆盖索引(只访问索引的查询(索引列和要查询的列一致)),减少select * 
  6.MySQL在使用不等于(!=或者<>)的时候无法使用索引会导致全表扫描
  7.is null,is not null 也无法使用索引
  8.like以通配符在这('%abc','%abc%')两种情况会索引实效变成全表扫描,'abc%'则不会,若要'%abc','%abc%'不失效,建议使用覆盖索引,且查询的字段要少于索引或者与索引一致,不使用select *。如为name,age,city建了索引,请这么使用:select name或者select age,或者select city或者select name,age,city。如果select name,age,city,email则会全表扫描
  9.字符串不加引号索引失效,
  10.少用or,用他来连接时索引会失效
  11.select * from A where exists (select 1 from where b.id=A.id)#当A表的数据系小于B表时,用exists优于in
  12.使用join代替子查询

性能分析

1.MySQL Query Optimizer(查询优化器)
  1.1MySQL中有专门负责优化select语句的优化器模块,主要功能:通过计算分析系统中收集到的统计信息,为客户端请求的query提供它认为最有的执行计划(它认为最优的数据检索方式,但不见得是DBA认为是最优的,这部分是最耗时间的)
  1.2当客户端向MySQL请求一条query,命令解析其模块完成请求分类,区别是select并转发给MySQL Query Optimizer时,MySQL Query Optimizer首先会对整条Query进行优化,处理掉一些常量表达式的预算,直接转换成常量值,并对query中的查询条件进行简化和转换,如去掉一些无用或显而易见的条件,结构调整等,然后分析query中的Hint信息(如果有),看显示Hint信息是否可以完全确定该query的执行计划,如果没有Hint或Hint信息不足以完全确定执行计划,则会读取所涉及对象的统计信息,根据query进行写相应的计算分析,然后再得出最后的执行计划。

2.MySQL常见瓶颈
  CPU:CPU在饱和的时候一般发生在数据装入内存或从磁盘读取数据时候
  IO:磁盘IO瓶颈发生在装入数据远大于内存容量的时候
  服务器硬件的性能瓶颈,top,free,iostat和vmstat来查看系统的性能状态

3.Explain
3.1explain+SQL语句顺序解释
  表的读取顺序(数字大的先读,相同的则由上而下读取)
  数据读取操作的操作类型
  哪些索引可以使用
  哪些索引被实际使用
  索引总长度
  表之间的引用
  每张表有多少行被优化器查询
  额外的信息(出现using index较好,出现using filesort较差)
3.2怎么用
  explain+SQL语句
  执行计划包含以下的信息

id select_type table type possible_keys key key_len ref rows extra

 

数据类型选择
  1.数字类型
    Float和double选择(尽量选择float)
    区分开TINYINT / INT / BIGINT,能确定不会使用负数的字段,建议添加 unsigned定义
    能够用数字类型的字段尽量选择数字类型而不用字符串类型的
  2.字符类型
    char,varchar,TEXT的选择:非万不得已不要使用 TEXT 数据类型,定长字段,建议使用 CHAR 类型(填空格),不定长字段尽量使用 VARCHAR(自动适应长度,超过阶段),且仅仅设定适当的最大长度
  3.时间类型
    按选择优先级排序DATE(精确到天)、TIMESTAMP、DATETIME(精确到时间)
  4.ENUM
    对于状态字段,可以尝试使用 ENUM 来存放
  5.避免使用NULL字段
    很难查询优化且占用额外索引空间

 

字符编码
  同样的内容使用不同字符集表示所占用的空间大小会有较大的差异,所以通过使用合适的字符集,可以帮助我们尽可能减少数据量,进而减少IO操作次数。
  1.纯拉丁字符能表示的内容,选择 latin1 字符编码
  2.中文可选用utf-8
  3.MySQL的数据类型可以精确到字段,所以当我们需要大型数据库中存放多字节数据的时候,可以通过对不同表不同字段使用不同的数据类型来较大程度减小数据存储量,进而降低 IO 操作次数并提高缓存命中率

order by优化
  重点:使用order by就需要看会不会产生filesort
  mysql支持两种方式排序,index和filesort,index效率高
  尽量使用Index方式排序,避免使用FileSort方式排序
  尽可能在索引列上完成排序操作,遵照索引列的最佳左前缀
  如果不在索引列上,filesort有两种算法:双路排序和单路排序
  双路排序:取一堆数据,要对磁盘进行两次扫描(mysql4.1之前,后来的版本增加了单路排序)
  单路排序:从磁盘读取查询需要的所有列,按照order by列在buffer对他们进行排序,然后扫描排序后的列表进行输出,效率快,但会使用更多的内存空间,因此注意调整sort_buffer_size和max_lenght_for_sort_data参数值(增大值),避免创建tmp文件从而进行多次I/O
group by优化
  和order by差不多
  先排序后分组,遵照索引列的最佳左前缀
  当无法使用索引列时,增大max_lenght_for_sort_data和sort_buffer_size的值
  where高于having,能在where限定的条件就不要去having限定了
优化总结
  1.开启慢查询日志
  2.expain+慢SQL分析
  3.show profile查询sql在mysql服务器里面的执行细节和生命周期情况
  4.sql数据库服务器的参数调优

posted @ 2019-08-05 15:30  冰叔博客  阅读(207)  评论(0编辑  收藏  举报