前言
俗话说的好“无规矩不成方圆”,在我们使用MySQL的过程中同样亦是如此,如果我们能达成一致的共识,那么开发过程中会减少一些不必要的争论,同时能让我们的整个开发更加规范。参考业界的一些共识和阿里数据库相关规范等,个人总结了一些库表设计、索引、SQL相关的规范,希望能对大家有所帮助,欢迎收藏~
一、命名规范
l 库名、表名、字段名必须使用小写字母,并采用下划线分割,不能超过32个字符
l 库名、表名、字段名必须?名知意。命名与业务、产品线等相关联
举例:遵循:{project名称} + "_" + 业务数据类型,比如“user_order”、“user_address”,如果数据表为全局系统表,可以不包含{project}前缀,比如“user”。
l 禁止使用中文字符、系统保留字、特殊符号命名
l 临时库、表名必须以tmp为前缀,并以日期为后缀。例 tmp_test01_20210310
l 备份库、表必须以bak为前缀,并以日期为后缀。例 bak_test01_20210310
二、基础规范
l 使用INNODB存储引擎(支持事务、支持更大并发量)
l 表字符集默认使用UTF8,需要存储表情请使用utf8 mb4
l 所有表都需要添加注释;除主键外的其他字段都需要增加注释。推荐采用英文标点,避免出现乱码
l 禁止在数据库中存储图片、大文件等大数据
l 禁止使用存储过程、触发器、函数
l 每张表数据量建议控制在1000W以内
l 禁止在线上做数据库压力测试
l 禁止从测试、开发环境直连数据库
l 单个实例数据库数量不超过50个
l 单个数据库容量不能超过300G
三、库表设计
l 禁止使用分区表
l 将大字段、访问频率低的字段拆分到单独的表中存储,分离冷热数据
l 推荐使用HASH进行散表,表名后缀使用十进制数,数字必须从0开始
l 按日期时间分表需符合YYYY[MM][DD][HH]格式,例如2021031001。年份必须使用4位数字表示。例如按日散表user_20210310、 按月散表user_202103。
l 采用合适的分库分表策略。例如千库十表、十库百表
l 创建表时必须显式指定表存储引擎类型和字符集,存储引擎统一使用innodb
l 表必须使用有序递增的整型字段做主键,字段类型用int或bigint,并且是无符号(unsigned)
l 不能使用外键
l 单表字段不能超过30个
l 单表记录数不能超过5000W,否则分表
l 建议表中添加三个字段:
create_time:记录创建时间,时间类型
update_time:记录修改时间,时间类型
version:“乐观锁”的版本标记,long型,默认为0
四、字段设计
l 建议使用UNSIGNED存储非负数值
l 建议使用INT UNSIGNED存储IPV4
l 用DECIMAL代替FLOAT和DOUBLE存储精确浮点数。例如货币、金融相关的数据
l INT类型固定占用4字节存储,例如INT(4)仅代表显示字符宽度为4位,不代表存储长度
l 强烈建议使用TINYINT来代替ENUM类型
l 不使用TEXT、BLOB类型
l 禁止在数据库中存储明文密码
l 使用VARBINARY存储大小写敏感的变长字符串或二进制内容
l 使用尽可能小的VARCHAR字段。VARCHAR(N)中的N表示字符数而非字节数,最大1024
l 区分使用DATETIME和TIMESTAMP。存储年使用YEAR类型。存储日期使用DATE类型。 存储时间(精确 到秒)建议使用TIMESTAMP类型(不过需要注意:TIMESTAMMP最大时间到2037年)
l 所有字段均定义为NOT NULL,定义其默认值,建议数字字段default 0,字符串字段尽量default "",最好不要default null
五、索引设计
l 单张表中索引数量不超过5个
l 单个索引中的字段数不超过5个
l 索引名必须全部使用小写
l 非唯一索引按照“idx_字段名称[_字段名称]”进行命名。例如idx_age_name
l 唯一索引按照“uniq_字段名称[_字段名称]”进行命名。例如uniq_age_name
l 组合索引建议包含所有字段名,过长的字段名可以采用缩写形式。例如idx_age_name_add
l 表必须有主键,推荐使用UNSIGNED自增列作为主键
l 不使用更新频繁地列作为主键
l 尽量不选择字符串列作为主键
l 唯一键由3个以下字段组成,并且字段都是整形时,可使用唯一键作为主键。其他情况下,建议使用自增列 或发号器作主键
l 禁止冗余索引
l 禁止重复索引
l 禁止使用外键
l 联表查询时,JOIN列的数据类型必须相同,并且要建立索引
l 不在低基数列上建立索引,例如“性别”等
l 选择区分度大的列建立索引。组合索引中,区分度大的字段放在前
l 对字符串使用前缀索引,前缀索引长度不超过10个字符;如果有一个CHAR(200)列,如果在前10个字符内,多数值是惟一的,那么就不要对整个列进行索引。对前10个字符进行索引能够节省大量索引空间,也可能会使查询更快。
l 不对过长的VARCHAR字段建立索引。建议优先考虑前缀索引,或添加CRC32或MD5伪列并建立索引。
l 合理创建联合索引,(a,b,c) 相当于 (a) 、(a,b) 、(a,b,c)。
l 合理使用覆盖索引减少IO,避免排序
l 不在索引列做计算,例如:where (id+1) < 200,不在索引列使用函数,比如date_format()
六、SQL规范
l 使用预编译语句prepared statement,只传参数,比传递SQL语句更高效,一次解析多次使用,且能避免SQL注入
l 用IN代替OR。SQL语句中IN包含的值不应过多,应少于1000个
l 禁止隐式转换。数值类型禁止加引号;字符串类型必须加引号
l 避免使用JOIN和子查询。必要时推荐用JOIN代替子查询。
l 避免在MySQL中进行数学运算和函数运算
l 减少与数据库交互次数,尽量采用批量SQL语句
l 拆分复杂SQL为多个小SQL,避免大事务
l 获取大量数据时,建议分批次获取数据,每次获取数据少于2000条,结果集应小于1M
l 用UNION ALL代替UNION
l 统计行数用COUNT(*)
l SELECT只获取必要的字段,禁止使用SELECT *
l SQL中避免出现now()、rand()、sysdate()、current_user()等不确定结果的函数
l INSERT语句必须指定字段列表,禁止使用 INSERT INTO TABLE()
l 禁止单条SQL语句同时更新多个表
l 避免使用存储过程、触发器、视图、自定义函数等
l 建议使用合理的分页方式以提高分页效率
假如有类似下面分页语句: SELECT * FROM table ORDER BY TIME DESC LIMIT 10000,10; 这种分页方式会导致大量的io,因 为MySQL使用的是提前读取策略。 推荐分页方式:
第1种:SELECT * FROM table WHERE TIME 第2种:SELECT * FROM table inner JOIN (SELECT id FROM table ORDER BY TIME LIMIT 10000,10) as t l 禁止在从库上执行后台管理和统计类功能的QUERY,必要时申请统计类从库 l 程序应有捕获SQL异常的处理机制,必要时通过rollback显式回滚 l 重要SQL必须被索引:update、delete的where条件列、order by、group by、distinct字段、多表join 字段 l 禁止使用%前导查询,例如:like “%abc”,无法利用到索引。 l 禁止使用负向查询,例如 not in、!=、not like l 使用EXPLAIN判断SQL语句是否合理使用索引,尽量避免extra列出现:Using File Sort、Using Temporary l 禁止使用order by rand() l 不能在不同数据类型的字段上进行比较,避免字段类型转换损失性能 l SQL语句在程序中传入的参数值类型必须与字段在数据库中的类型相同 l INSERT语句必须写上具体的字段名称,写成:insert into table(字段1,字段2,...) values(值1,值2,...)。 l 在做批量更新/插入操作时,建议操作的数据行数不要太多,也不要太少,一般100~200行提交一次,避免频繁io操作 l 前端程序不允许使用set sql_mode和set tx_isolation(会话级事务隔离级别)语句 l 不能使用SELECT … FOR UPDATE语法,它会扩大意向锁范围即表锁,影响数据库的并发效率 l 新数据架构业务尽量join表不能超过3个 七、行为规范 l 表结构变更必须通知DBA进行审核 l 禁止有super权限的应用程序账号存在 l 禁止有DDL、DCL权限的应用程序账号存在 l 批量导入、导出数据必须通过DBA审核,并在执行过程中观察服务 l 产品出现非数据库导致的故障时,如被攻击,必须及时通DBA,便于维护服务稳定 l 业务部门程序出现BUG等影响数据库服务的问题,必须及时通知DBA,便于维护服务稳定 l 业务部门推广活动或上线新功能,必须提前通知DBA进行服务和访问量评估,并留出必要时间以便DBA完成扩容 l 出现业务部门人为误操作导致数据丢失,需要恢复数据的,必须第一时间通知DBA,并提供准确时间点、 误操作语句等重要线索。 l 提交线上建表改表需求,必须详细注明涉及到的所有SQL语句(包括INSERT、DELETE、UPDATE),便于DBA进行审核和优化 l 对同一个表的多次alter操作必须合并为一次操作 l 不要在MySQL数据库中存放业务逻辑 l 对特别重要的库表,提前与DBA沟通确定维护和备份优先级 l 不在业务高峰期批量更新、查询数据库 八、安全规范 1.服务器 l 必须分离MySQL的online,beta,dev环境,不在线上环境直接开发和做任何测试 2.账户权限 l 一个账号对应一个数据库,应用账户只能允许访问对应的数据库。 l 应用账号权限默认开启select/insert/update/delete/execute的权限。 l 每个应用建立一个账号,默认是可读写。 如果只读或只写,加_w,_r。 3.数据获取 l 有敏感信息的数据导出需要上级审批,防止数据泄露。 l 有批量导出数据的需求,需要告知DBA,开发人员不能直接到线上数据库批量导出数据。