MySQL开发规范
一、命名规范
- 命名要见名知意,全部使用小写字母,多个单词之间使用下划线连接禁止使用中文拼音! 例: t_article_detail
- database
 db_[数据库名]
 例如:db_hms
- table
 t_[表名]
 例如:t_school
- index
 idx_[普通索引]、uk_[唯一索引]
 例如:idx_uid、uk_record_id
- view
 v_[视图名]
- function(默认禁止使用)
 f_[方法名]
- procedure(默认禁止使用)
 p_[存储过程名]
- event(默认禁止使用)
 e_[事件名]
二、建表规范
- 所有列名、表名都要有注释 
- 字符集统一使用utf8mb4,排序规则使用utf8mb4_general_ci(特殊例外) 
 排序规则默认使用utf8mb4_general_ci,列值如果需要根据大小写过滤则配置对应列排序规则为utf8mb4_bi,如验证码、密码
### 字符集使用utf8mb4,默认使用utf8mb4_general_ci
CREATE TABLE t_test (
 id int(11) NOT NULL AUTO_INCREMENT COMMENT '自增id',
 val varchar(20) NOT NULL DEFAULT '' COMMENT '值',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测试表';
### 特殊列需要根据大小写过滤,配置列排序规则utf8mb4_bin
CREATE TABLE `t_test` (
 id int(11) NOT NULL AUTO_INCREMENT COMMENT '自增id',
 pwd varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '密码',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测试表';
- 字段名禁止使用数据库保留关键字 
 例如:- date、- datetime、- desc、- range、- match、- comment、- add等
 所有MySQL保留关键字详见 mysql5.7关键字和保留字
- 表的主键的命名建议依据表的含义+_id 
 例如:用户表t_user 主键为user_id
- 新建表需要创建字段 
 【必选】创建时间- create_time,修改时间- update_time;【可选】是否可用- is_flag
 CREATE TABLE `t_test` (
  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增id',
  `is_flag` tinyint(2) unsigned NOT NULL DEFAULT '1' COMMENT '是否可用,1是,0否',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '测试表'
;
- 每个表都需要有主键,自增主键使用unsigned
 建议使用自增键作为主键,避免使用uuid、字符串等做主键,禁止无主键
- 小数类型使用 decimal ,禁止使用 float 和 double
 说明:float 和 double 在存储的时候,存在精度损失的问题。decimal(M,D),M表示总位数,D表示小数点后位数;
 例如:decimal(5,2),整数部分可以存储3位,小数部分可以存储2位
- 数值类型的字段只有正数时,指定unsigned
 CREATE TABLE `t_test` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增id',
  `age` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '只有正数,指定unsigned'
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '测试表'
;
- 存储货币,类型使用整型,单位为分
- 字段设置默认值,尽量避免空值null
- 表之间的关联字段,字段类型和字符集要保持一致
#t_class的id和t_student的class_id关联,两者的字段类型和字符集要一致
select t_class.*,t_student.* 
from t_student  
 left join t_class on t_class.id=t_student.class_id;
- 表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是unsigned tinyint( 1 表示是,0 表示否 ) 。
 说明:任何字段如果为非负数,必须是unsigned。
 例如:表达逻辑删除的字段名 is_deleted ,1 表示删除,0 表示未删除。
- varchar长度限制
 建议不要超过5000,如果存储长度大于此值,定义字段类型为 text,独立出来一张表,用主键来关联,避免影响其它字段索引效率。
- 删除自增初始值
 说明:有的表结构通过测试环境导出,会含有AUTO_INCREMENT=N,请将其删除再提交。
- 修改同一张多个字段,合并为单条SQL
 说明:经常有同事对同一张表添加多个字段,分成多条SQL,带来的影响是每执行一条DDL都会对该表重建和锁表。
#反例,添加t_task多个字段
ALTER TABLE t_task ADD identity_type  tinyint(4) DEFAULT '1' COMMENT '用户身份类型: 非会员:0、全员:1、白银会员:2、超级会员:3;';
ALTER TABLE t_task ADD online_time date DEFAULT NULL COMMENT '上线时间 格式: YYYY-MM-DD';
ALTER TABLE t_task ADD offline_time date DEFAULT NULL COMMENT '下线时间 格式: YYYY-MM-DD';
#正例
ALTER TABLE t_task 
  ADD identity_type  tinyint(4) DEFAULT '1' COMMENT '用户身份类型: 非会员:0、全员:1、白银会员:2、超级会员:3;',
  ADD online_time date DEFAULT NULL COMMENT '上线时间 格式: YYYY-MM-DD',
  ADD offline_time date DEFAULT NULL COMMENT '下线时间 格式: YYYY-MM-DD';
- 有限类型选项,选择【够用】类型 
 说明:不同类型取值范围不一样,有的字段取值就0、1、2,10以内,字段类型可选择为tinyint- 类型 - 取值范围(有符号) - 取值范围(无符号) - tinyint - -128~127 - 0~255 - smallint - -32768~32767 - 0~65535 - mediumint - -8388608~8388607 - 0~16777215 - int - -2147483648~2147483647 - 0~4294967295 
- 禁止使用外键 
- 基础字段长度标准 
 说明:经常有表需要添加字段【操作人名称】(operation_name/user_name)、图片链接地址(url)等,可按此标准创建(需开发确认),防止字段长度过短被截取或报错。- 字段 - 建议长度 - 备注 - operation_name/user_name - varchar(50) - 操作人名称 - url - varchar(200) - 图片链接地址 
- 表限制 列数:单表列数小于30 行数:以三年内的数据量,超过 500 万行或者单表容量超过 2 GB ,建议进行分库分表。 
- 时间字段类型建议使用datetime,而不是timestamp 
 说明:虽然timestamp占用空间比datetime小,但仅能存储到- 2038-01-19
- 字段类型tinyint(1)建议更改为tinyint(2) 说明:括号中数字跟存储的大小范围无关,但canal会将tinyint(1)类型解析成bit导致同步错误。 
22. DRDS分布式事务
drds支持2PC,但在同一个事务里,涉及insert的表都需要创建全局序列Sequence,否则会报错。(目前仅dbfileserver有使用)   
三、索引规范
- 索引命名
 以idx_开头,单个字段为列名全称,组合索引的列名之间通过下划线关联,列名内取消下划线
alter table t_test add index idx_student_id(student_id);  #单个字段,列名全称
alter table t_test add index idx_classid_studentid(class_id,student_id);  #多个字段,列名内取消下划线,列名之间通过下划线关联
- 索引限制 单表索引个数建议在5个以内,单个索引字段不超过5个 
- 禁止左模糊搜索或全模糊搜索 
#正例
select * from t_student where name like '中%';
 
#反例
select * from t_student where name like '%中';
select * from t_student where name like '%中%';
- varchar字段建立索引,指定索引长度
 正常没必要对整个字段建立索引,一般长度20能区分90%数据。
 varchar长度在50以内,可以直接使用整个字段建立索引,超过50以后使用count(distinct left(列名, 索引长度))/count(*)的区分度来确认索引长度。
#name字段长度为100
alter table t_test add index idx_name(name(20));
- 避免在区分度不高,频繁更新列上建立索引
- 表数据量在1000以内,可不用建索引
四、SQL规范
- 尽量使用简单SQL
 对复杂SQL进行拆分,化简成简单SQL,尽量减少多表关联。
- 避免在索引列进行运算导致索引失效引发全表扫描
#反例:对列create_time进行date_format运算
select * from t_student where date_format(create_time,'%Y-%m-%d')='2021-02-24';
 
#正例:转换成对值的判断
select * from t_student where create_time >= '2021-02-24' and create_time < '2021-02-25';
- 避免使用大事务造成执行锁定时间,同时导致备库只读节点数据延迟
- 查询时显示指定要查询列,避免直接select *
- 利用延迟关联或者子查询优化超多分页场景
#原始SQL
SELECT * FROM 表1 where 条件 LIMIT 100000,20;
 
#建议,延迟关联,先查询主键id,再通过关联出所有字段
SELECT a.* FROM 表1 a, (select id from 表1 where 条件 LIMIT 100000,20 ) b where a.id=b.id;

Comments