mysql数据库优化以及规范

                    

一.基础规范

1. 所有的数据库对象名称必须使用小写字母并用下划线分割(MySQL大小写敏感,名称要见名知意,最好不超过32字符)

2. 所有的数据库对象名称禁止使用MySQL保留关键字(如 desc、range、match、delayed 等,请参考 MySQL官方保留字 )

3.临时库表必须以tmp为前缀并以日期为后缀(tmp_)

4. 备份库和库必须以bak为前缀并以日期为后缀(bak_) 

5.所有存储相同数据的列名和列类型必须一致。(在多个表中的字段如user_id,它们类型必须一致)

6. 禁止在数据中存储图片,文件二进制数据(使用文件服务器)

7. 禁止跨库查询(为数据迁移和分库分表留出余地,降低耦合度,降低风险)

8. 禁止select * 查询(消耗更多的cpu和io及网络带宽资源,无法使用覆盖索引),SELECT语句务必指明字段名称。

9. 禁止使用不含字段列表的insert语句(不允许insert into t values(‘a’,‘b’,‘c’))

10. 尽量把所有的字段定义为NOT NULL并设默认值

(1)NULL的列使用索引,索引统计,值都更加复杂,MySQL更难优化

(2)NULL需要更多的存储空间

(3)NULL只能采用IS NULL或者IS NOT NULL,而在=/!=/in/not in时有大坑

11. mysql5.5之前默认的存储的引擎是myisam,没有特殊要求,所有的表必须使用innodb(innodb好处支持失误,行级锁,高并  发下性能更好,对多核,大内存,ssd等硬件支持更好)

12. 数据库和表的字符集尽量统一使用utf8(字符集必须统一,避免由于字符集转换产生的乱码,汉字utf8下占3个字节)

13. 所有表和字段都要添加注释COMMENT,从一开始就进行数据字典的维护

14. 尽量控制单表数据量的大小在500w以内,超过500w可以使用历史数据归档,分库分表来实现(500万行并不是MySQL数据库的限制。过大对于修改表结构,备份,恢复都会有很大问题)

15. 尽量做到冷热数据分离,减小表的宽度,即建议将大字段,访问频度低的字段拆分到单独的表中存储,分离冷热数据

(mysql限制最多存储4096列,行数没有限制,但是每一行的字节总数不能超过65535。列限制好处:减少磁盘io,保证热数据的内存缓存命中率,避免读入无用的冷数据)

16. in 操作能避免则避免,若实在避免不了,需要仔细评估 in 后边的集合元素数量,控制在 1000 个之内

17. 根据业务区分使用数据类型,优先选择存储最小的数据类型。

(1)是否有效用bit即可。

(2)根据业务区分使用tinyint/int/bigint,分别会占用1/4/8字节,

(3)根据业务区分使用char/varchar

对于字段长度固定,或者长度近似的业务场景,适合使用char,能够减少碎片,查询性能高,对于字段长度相差较大,或者更新较少的业务场景,适合使用varchar,能够减少空间

(4)根据业务区分使用datetime/timestamp

前者占用8个字节,后者占用4个字节,存储年使用YEAR,存储日期使用DATE,存储时间使用datetime

timestamp范围:‘1970-01-01 00:00:01.000000’到 ‘2038-01-19 03:14:07.999999’;

datetime范围:’1000-01-01 00:00:00.000000’ 到 ‘9999-12-31 23:59:59.999999’。

(5)同财务相关的金额数据,采用decimal类型(不丢失精度,禁止使用 float 和 double)

18.不要使用count(列名)或count(常量)来替代count(*),count(*)是SQL92定义的标准统计行数的语法。

说明:count(*)会统计值为NULL的行,而count(列名)不会统计此列为NULL值的行。

19. 尽量避免使用外键

20. 避免使用Text或是Blob类型

21. 尽量不要使用物理删除

(即直接删除,如果要删除的话提前做好备份),而是使用逻辑删除,使用字段enable做逻辑删除,0表示删除或者失效,1表示有效

22. 使用 ISNULL()来判断是否为 NULL 值。

23 当只需要一条数据的时候,使用limit 1

24 区分in和exists, not in和not exists 原则是小表驱动大表

select * from 表A where id in (select id from 表B)

上面sql语句相当于

select * from 表A where exists(select * from 表B where 表B.id=表A.id)

区分in和exists主要是造成了驱动顺序的改变,如果是exists,那么以外层表为驱动表,先被访问,如果是IN,那么先执行子查询。所以IN适合于外表大而内表小的情况;EXISTS适合于外表小而内表大的情况。

关于not in和not exists,推荐使用not exists,不仅仅是效率问题,not in可能存在逻辑问题。如何高效的写出一个替代not exists的sql语句?

原sql语句

select colname … from A表 where a.id not in (select b.id from B表)

高效的sql语句

select colname … from A表 Left join B表 on where a.id = b.id where b.id is null

取出的结果集:A表不在B表中的数据

25. 每个innodb表必须有一个主键,选择自增id(不能使用更新频繁的列作为主键,不适用UUID,MD5,HASH,字符串列作为主键)

26. 在代码中写分页查询逻辑时,若 count 为 0 应直接返回,避免执行后面的分页语句

二、从索引出发的规范

27. 避免建立冗余索引和重复索引(冗余:index(a,b,c) index(a,b) index(a))

28. 禁止给表中的每一列都建立单独的索引

29. 区分度最高的列放在联合索引的最左侧

30. 避免使用双%号和like,搜索严禁左模糊或者全模糊(如果需要请用搜索引擎来解决。索引文件具有 B-Tree 的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索)

31. 禁止使用order by rand()进行随机排序

32. 禁止where从句中对列进行函数转换和计算,以及避免隐式类型转换(例如:where age+2>18 会使age列上的索引失效。

33. 尽量使用 union all 代替 union

34. 尽量避免使用子查询,可以把子查询优化为join操作(子查询的结果集无法使用索引,子查询会产生临时表操作,如果子查询数据量大会影响效率,消耗过多的CPU及IO资源)

35.【建议】 超过三个表禁止 join。(需要 join 的字段,数据类型必须绝对一致;多表关联查询时,保证被关联的字段需要有索引。即使双表 join 也要注意表索引、SQL 性能。)

36. 在varchar字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度即可。

37. SQL 性能优化的目标:至少要达到 range 级别,要求是 ref 级别,如果可以是 consts最好

38. 限制每张表上的索引数量,建议单表索引不超过5个(索引会增加查询效率,但是会降低插入和更新的速度)

39. 如果有 order by 的场景,请注意利用索引的有序性。order by 最后的字段是组合,索引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章