《高性能MySQL》——这本书都有的
“字段”优化总结
1)尽量使用TINYINT、SMALLINT、MEDIUM_INT作为整数类型而非INT,如果非负则加上UNSIGNED;
2)VARCHAR的长度只分配真正需要的空间;
3)使用枚举或整数代替字符串类型;
4)尽量使用TIMESTAMP而非DATETIME;
5)单表不要有太多字段,建议在20以内;
6)避免使用NULL字段,很难查询优化且占用额外索引空间;
7)用整型来存IP。
“索引”优化总结
1)索引并不是越多越好,要根据查询有针对性的创建,考虑在WHERE和ORDER BY命令上涉及的列建立索引,可根据EXPLAIN来查看是否用了索引还是全表扫描;
2)应尽量避免在WHERE子句中对字段进行NULL值判断,否则将导致引擎放弃使用索引而进行全表扫描。
3)值分布很稀少的字段不适合建索引,例如"性别"这种只有两三个值的字段。
4)字符字段只建前缀索引。
5)字符字段最好不要做主键。
6)不用外键,由程序保证约束。
7)尽量不用UNIQUE,由程序保证约束。
8)使用多列索引时主意顺序和查询条件保持一致,同时删除不必要的单列索引。
索引的优化
联合索引最左前缀原则
复合索引遵守「最左前缀」原则,查询条件中,使用了复合索引前面的字段,索引才会被使用,如果不是按照索引的最左列开始查找,则无法使用索引。
比如在 (a,b,c) 三个字段上建立联合索引,那么它能够加快 a|(a,b)|(a,b,c) 三组查询的速度,而不能加快 b|(b,a) 这种查询顺序。
另外,建联合索引的时候,区分度最高的字段在最左边
不要在列上使用函数,这将导致索引失效而进行全表扫描。
例如:
select * from student where YEAR(create_time) <= '2018';
即使 date 上建立了索引,也会全表扫描,可以把计算放到业务层,这样做不仅可以节省数据库的 CPU,还可以起到查询缓存优化效果。
负向条件查询不能使用索引
负向条件有:!=、<>、not in、not exists、not like 等。
select * from student where status != 1 and status != 2;
可以使用 in 进行优化:
select * from student where status in (0,3)
使用覆盖索引
所谓覆盖索引,是指被查询的列,数据能从索引中取得,而不用通过行定位符再到数据表上获取,能够极大的提高性能。
可以定义一个让索引包含的额外的列,即使这个列对于索引而言是无用的。
避免强制类型转换
当查询条件左右两侧类型不匹配的时候会发生强制转换,强制转换可能导致索引失效而进行全表扫描。
如果 phone 字段是 varchar 类型,则下面的 SQL 不能命中索引:
select * from user where phone=12345678901;
可以优化为:
select * from user where phone='12345678901';
范围列可以用到索引
范围条件有:<、<=、>、>=、between 等。
范围列可以用到索引,但是范围列后面的列无法用到索引,索引最多用于一个范围列,如果查询条件中有两个范围列则无法全用到索引。
更新频繁、数据区分度不高的字段上不宜建立索引
更新会变更 B + 树,更新频繁的字段建立索引会大大降低数据库性能。
「性别」这种区分度不大的属性,建立索引没有意义,不能有效过滤数据,性能与全表扫描类似。
区分度可以使用 count (distinct (列名))/count (*) 来计算,在 80% 以上的时候就可以建立索引。
索引列不允许为 null
单列索引不存 null 值,复合索引不存全为 null 的值,如果列允许为 null,可能会得到不符合预期的结果集。
避免使用 or 来连接条件
应该尽量避免在 where 子句中使用 or 来连接条件,因为这会导致索引失效而进行全表扫描,
虽然新版的 MySQL 能够命中索引,但查询优化耗费的 CPU 比 in 多。
模糊查询
前导模糊查询不能使用索引,非前导查询可以。
“查询SQL”优化总结
1)可通过开启慢查询日志来找出较慢的SQL;
2)不做列运算:SELECT id WHERE age + 1 = 10,任何对列的操作都将导致表扫描,
它包括数据库教程函数、计算表达式等等,查询时要尽可能将操作移至等号右边;
3)sql语句尽可能简单:一条sql只能在一个cpu运算;大语句拆小语句,减少锁时间;一条大sql可以堵死整个库;
4)不用SELECT *;
5)OR改写成IN:OR的效率是n级别,IN的效率是log(n)级别,in的个数建议控制在200以内;
6)不用函数和触发器,在应用程序实现;
7)避免%xxx式查询;
8)少用JOIN;
9)使用同类型进行比较,比如用'123'和'123'比,123和123比;
10)尽量避免在WHERE子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描;
11)对于连续数值,使用BETWEEN不用IN:SELECT id FROM t WHERE num BETWEEN 1 AND 5;
12)列表数据不要拿全表,要使用LIMIT来分页,每页数量也不要太大。
“引擎”的选择
目前广泛使用的是MyISAM和InnoDB两种引擎。
【MyISAM】:
MyISAM引擎是MySQL 5.1及之前版本的默认引擎,它的特点是:
1)不支持行锁,读取时对需要读到的所有表加锁,写入时则对表加排它锁;
2)不支持事务;
3)不支持外键;
4)不支持崩溃后的安全恢复;
5)在表有读取查询的同时,支持往表中插入新纪录;
6)支持BLOB和TEXT的前500个字符索引,支持全文索引;
7)支持延迟更新索引,极大提升写入性能;
8)对于不会进行修改的表,支持压缩表,极大减少磁盘空间占用。
【InnoDB】:
InnoDB在MySQL 5.5后成为默认索引,它的特点是:
1)支持行锁,采用MVCC来支持高并发;
2)支持事务;
3)支持外键;
4)支持崩溃后的安全恢复;
5)不支持全文索引。
总体来讲,MyISAM适合SELECT密集型的表,而InnoDB适合INSERT和UPDATE密集型的表。
系统调优参数、升级硬件、读写分离、缓存、垂直拆分、水平拆分