MYSQL-索引&SQL优化-IM

索引选择策略:

索引的选择性(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

你可能感兴趣的:(MYSQL-索引&SQL优化-IM)