针对SQL语句的优化,我们不要一上来就 回答添加索引,这样显得不太专业.
有以下步骤分析:
1.回归到表的设计层面,是不是表结果设计不合理,数据类型是否合理,大字段有没有分离到另一个表.
2. 大表碎片的整理是否完善.
在开发过程中,发现表的数据删除了,但是表的 属性中查看 ,ROWS 行数并没有减少.
通过 show table status like '%table_name%'
碎片大小= (数据总大小-实际表空间文件大小)/1024/1024 单位MB.
数据总大小=data_length+index_length
实际表空间大小= rows 乘以 avg_row_length;
Innodb表清楚碎片的一种方法:
2.1 alter tabile table_name engine=innodb; 重新整理一遍全表数据,整理之后的数据连 续性好,全表扫描变快,表空间文件也变小了,节约了磁盘空间,缺点就是给整表加了写 锁,需要时间比较长,业务高峰期不建议使用.(方法一)
2.2 备份原表数据,然后删除,重新导入到 新表中 (与原表结构一样,删除原表之后,表名称 和原表一样) pt-online-schema-change,可以在线整理表结果,收集碎片,给大表添加 字段和所以,避免出现锁表导致阻塞读写的操作(方法二)
MyISAM表:
optimize table tablename
3.表的统计信息是不是准确的
select * from information_schema.tables where table_name='table_name'
4. 审查表的执行计划,判断字段上面有没有合适的索引.
5. 针对索引的选择性,建立合适的索引,(涉及大表的DDL操作问题,应该建立新的表,导入数据过 来,建立好索引之后,在合适的时机把旧表删除,新表命名为旧表的名称)
通过 select count(distinct name)/count(*) from t; 查看字段的选择性,选择性越高,重复值就越少,非常适合建立索引. 联合索引的最左原则,选择选择度高的在前面.
创建索引之后,再查看一下执行计划,对比两次结果,看是否效率提高了.
建立索引的三个经常:
5.1 经常被查询的列 (where条件的后面)
5.2 经常用于表连接的列(表连接的字段要和另一个表的连接字段类型相同)
5.3 经常排序分组的列(order by 或者 group by的字段)
如何查看mysql的执行计划(sql语句前面添加explain):
先看 type,如果出现all关键字,后面的就不用看了,全表扫描
再看 key列,看是否使用了所以,null代表没有索引
再看rows 列,代表执行计划中药被扫描的行,值越大,扫描的行越多,性能越差,扫描的行超过全表的30%,不会使用索引.
最后看 extra 列,如果有 Using filesort 或者 Using temporary这样的关键字出现,是很影响数据库性能的.
ICP: 5.6之后,直接把过滤操作在存储引擎层,把满足的行返回,5.6之前需要索引定位行,然后返回给server.再去为这些数据进行where后的添加过滤, ICP能减少引擎访问基表的次数和Server层访问存储引擎的次数.
MRR: 通过 mrr=on 和 mrr_cost_based=on 两个参数开启. 普通索引能查询到重复值,就有主键值的集合返回.
MRR就是把普通索引的叶子结果上的主键值的集合存储到 read_rnd_buffer中,然后在该buffer中对主键值排序,最后利用已经排序好的主键值的集合,去访问表的数据,这样就由原来的随机IO 变成了 顺序IO,降低了查询过程中的IO开销.
生成环境中的 read_rnd_buffer的值 可以在 4-8M之间调整.
BKA: BKA的原理很简单,对于多表join语句,当MYSQL使用索引访问第二个join表时,
使用一个 join_buffer来收集第一个操作对象生成的相关列值. BKA构建好 key后,批量传给 引擎层 做索引查找, key是通过 MRR 接口提交给 引擎的,这样一来 相当于批量 MRR
BKA需要 MRR开启才有效. 通过 optimizer_switch参数的 batched_key_access选项来控制.
set global optimizer_switch='mrr=on,mrr_cost_based=on';
set global optimizer_switch='batched_key_access=on';