索引选择策略:
索引的选择性(Selectivity),是指不重复的索引值(也叫基数,Cardinality)与表记录数(#T)的比值:取值范围为(0, 1],选择性越高的索引价值越大[即索引列值越离散索引价值越大,如:性别就男女2个值,在性别列上建立索引无法达到快速定位缩小行范围目的]
SELECT count(DISTINCT(first_name)) / count(*)AS Selectivity FROM employees;
SELECT count(DISTINCT(concat(first_name,last_name)))/count(*)AS Selectivity FROM employees;
SELECT count(DISTINCT(concat(first_name,left(last_name,4))))/count(*) AS Selectivity FROM employees;
选择索引字段原则:
数据类型: 选范围小的 & 选类型简单的 & 尽量not null
(mysql难以优化包含null字段查询,有必要时设置一个默认值)
字段值: 值域尽量离散,区分度高
索引优化策略:
1. 【强制】业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引。 说明:不要以为唯一索引影响了insert速度,这个速度损耗可以忽略,但提高查找速度是明显的;另外,即使在应用层做了非常完善的校验控制,只要没有唯一索引,根据墨菲定律,必然有脏数据产生。
2.【强制】 超过三个表禁止join(消耗较多内存,产生临时表)。需要join的字段,数据类型必须绝对一致;多表关联查询时,保证被关联的字段需要有索引。 说明:即使双表join也要注意表索引、SQL性能。
3.【强制】在varchar字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度即可。 说明:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为20的索引,区分度会高达90%以上,可以使用count(distinct left(列名, 索引长度))/count(*)的区分度来确定。
4.【强制】页面搜索严禁左模糊或者全模糊(造成索引失效),如果需要请走搜索引擎来解决。 说明:索引文件具有B-Tree的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引。右模糊能命中索引
5.【推荐】如果有order by的场景,请注意利用索引的有序性。order by 最后的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现file_sort的情况,影响查询性能。 正例:where a=? and b=? order by c; 索引:a_b_c 反例:索引中有范围查找,那么索引有序性无法利用,如:WHERE a>10 ORDER BY b; 索引a_b无法排序。
6.【推荐】利用覆盖索引来进行查询操作,避免回表。 说明:如果一本书需要知道第11章是什么标题,会翻开第11章对应的那一页吗?目录浏览一下就好,这个目录就是起到覆盖索引的作用。 正例:能够建立索引的种类:主键索引、唯一索引、普通索引,而覆盖索引是一种查询的一种效果,用explain的结果,extra列会出现:using index。
7.【推荐】利用延迟关联或者子查询优化超多分页场景。[优化深度分页问题]
说明:MySQL并不是跳过offset行,而是取offset+N行,然后返回放弃前offset行,返回N行,那当offset特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过特定阈值的页数进行SQL改写。 正例:先快速定位需要获取的id段,然后再关联:
正例:先快速定位需要获取的id段,然后再关联:
SELECT a.* FROM 表1 a, (select id from 表1 where 条件 LIMIT 100000,20 ) b where a.id=b.id
8.【推荐】 SQL性能优化的目标:至少要达到 range 级别,要求是ref级别,如果可以是consts最好。 说明: 1)consts 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。 2)ref 指的是使用普通的索引(normal index)。 3)range 对索引进行范围检索。 反例:explain表的结果,type=index,索引物理文件全扫描,速度非常慢,这个index级别比较range还低,与全表扫描是小巫见大巫。
9.【推荐】建组合索引的时候,区分度最高的在最左边。 正例:如果where a=? and b=? ,a列的几乎接近于唯一值,那么只需要单建idx_a索引即可。 说明:存在非等号和等号混合判断条件时,在建索引时,请把等号条件的列前置。如:where a>? and b=? 那么即使a的区分度更高,也必须把b放在索引的最前列。
10.【参考】创建索引时避免有如下极端误解: 1)误认为一个查询就需要建一个索引。 2)误认为索引会消耗空间、严重拖慢更新和新增速度。 3)误认为唯一索引一律需要在应用层通过“先查后插”方式解决。
11.表必须有主键建议使用自增id作为主键,建议不要选择字符串作为主键(如:身份证号、UUID),空间占用大&索引效率低。
12.合理创建复合索引(避免冗余)-最左前缀: index(a,b,c) 相当于建立index(a),index(a,b),index(a,b,c)
13.不要索引列上进行数学或函数运算-会导致索引失效
反例: SELECT c2,c3 FROM t WHERE date(c1) = ‘2016-10-15’
14.对字符列使用前缀索引:区分度决定索引长度[count(distinct left(列名, 索引长度))/count(*)的区分度],一般不超过20
15.不使用 左模糊或者全模糊(造成索引失效),右模糊可以命中索引
反例: SELECT c2,c3 FROM t WHERE c4 like ‘%???%’
16.不使用反向查询,如: not in / not like -无法使用索引,全表扫描。
17.避免隐士类型转换,导致索引失效: 类型不匹配导致
select user_id from user_info where user_id = '123'
18.最左前缀,最多利用一个范围条件:2个及以上导致索引失效
正例:
SELECT*FROM employees.titles WHERE emp_no<'10010'and title='Senior Engineer';
反例:
SELECT*FROM employees.titles
WHERE emp_no<'10010'
AND title='Senior Engineer'
AND from_date BETWEEN'1986-01-01'AND'1986-12-31';
19.in 代替or ,in的值不超过1000个。
20.禁用select * ,使用哪些列就查询哪些列。(选择更多列意味占用更多buffer缓冲区,如果超过最大buffer缓存区能容纳size则会进行IO读取建立临时表等操作,速度降低。所以尽量查我们需要的列)无法使用覆盖索引&降低解析成本。
21.能UNION ALL就不要UNION(UNION需要去重,会产生临时表)
22.不要使用外键:高并发场景影响性能。
23.尽量不使用TEXT、BLOB类型,如果使用 拆分大字段和访问频率低的字段,分离冷热数据。
24.分表策略: hash or 日期时间(yyyy-mm-dd格式)
运维好习惯:
1.关闭QUERY CACHE
–绝大多数情况下鸡肋,最好关闭
–QC锁是全局锁,每次更新QC的内存块锁代价高,出现Waiting for query cache lock状态的频率很高
–实例启动前设置query_cache_type = 0 & query_cache_size =0
2.使用独立undo表空间
–避免ibdata1文件存储空间暴涨
–MySQL 5.6开始支持独立表空间
–MySQL 5.7还可以回收已经purge的表空间
–提高file i/o能力,并适当增加purge线程数innodb_purge_threads
–事务及时提交,不要积压。并且默认打开autocommit = 1
3.启用thread pool
–应对突发短连接
–extra port
•没thread pool怎么办
–想办法启用连接池或其他替代方案
–适当调低超时阈值,减少空闲连接
4.几个关键选项
–innodb_buffer_pool_size,约物理内存的50% ~ 70%
–innodb_log_file_size,5.5及以上2G+,5.5以下建议不超512M
–innodb_flush_log_at_trx_commit,0=>最快数据最不安全,1=>最慢最安全,2=>折中
–innodb_max_dirty_pages_pct,25%~50%为宜
–max_connections,突发最大连接数的80%为宜,过大容易导致全部卡死
5.启用辅助监控机制
–干掉超过N秒的SQL
–干掉疑似注入SQL
–干掉长时间不活跃的sleep连接
6.autocommit
–避免某些行锁被长时间持有,影响tps
–更严重时,可能连接数暴涨,导致整个实例挂掉
–采用gui客户端连接时,记得及时关闭连接,或设置超时阈值以及自动提交,否则容易发生行锁等待问题
关于EXPLAIN:
–关键业务SQL上线前,都要EXPLAIN确认其执行计划
–或提前分析slow query log,防患未然
–EXPLAIN中如果有Using temporary、Using filesort、或type=ALL时,尽量想办法进行优化
参见:
http://www.cnblogs.com/hellojesson/p/6001685.html