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


