MySQL 相关规范

流程规范

流程图.jpg
  1. 服务正式上线前,一定要check下线上数据库改动已经上线。不然会引起线上事故!
  2. 测试环境也要有,不然测试环境后面会越来越难建设。

设计规范

规范共分为【强制】、【推荐】、【参考】三个等级,优先级从高至低,如违反【强制】规范Reviewer应当打回。

命名规范

【强制】表的命名最好是“业务名称_表的作用” ,无需额外的数据库名开头。

对于bits数据库来说,正例:app_build_config,workflow_job; 反例:bits_app_info,bits_xxx;

【强制】表名、字段名必须使用小写字母或****数字,禁止出现数字开头,禁止两个下划线中间只 出现数字。正例:app_user,app_config,level3_name 反例:AppUser,rdcConfig,level_3_name

【强制】表名使用单数。 说明:表名应该仅仅表示表里面的实体内容,不应该表示实体数量,符合表达习惯。

【强制】索引名字的前缀必须idx_,唯一约束/索引的前缀必须uk_

【强制】所有命名必须使用全名,有默认约定的除外,如果超过 30 个字符,使用缩写

【强制】每个字段和表必须提供清晰的注释,现在没有注释 rds 不让建表。


【推荐】库的命名最好是“系统名称_子系统名”, 正例 bits_pipeline,bits_ttp。

字段规范

【强制】必加的三个字段

  • id(unsigned bigint),单表时自增。防止枚举时用id generator生成
  • create_time(timestamp),用于记录主动创建时间,默认值:current_timestamp
  • update_time(timestamp),用于记录最后更新时间,默认值: current_timestamp

【强制】每个表不超过30个字段

【强制】如果存储的字符串长度固定,使用 char 定长字符串类型

【强制】文本数据尽量用varchar ,变长存储,更省存储空间,长度不要超过 2700,如果存储长 度大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索引效率。

【强制】存储字段如果为非负数,默认加上UNSIGNED。

【强制】小数类型为 decimal,禁止使用 float 和 double。decimal不存在精度损失,数据类型decimal(p,s) 需要分别指定小数的最大位数(p)和小数位的数量(s)。

【强制】如果修改字段含义或对字段表示的状态追加时,需要及时更新字段注释。

【强制】业务中选择性很少的状态、****类型 等字段推荐使用 TINYINT。从1开始枚举,并且将具体含义写在字段备注里。禁止使用 bool 来存状态。

【强制】索引字段不要设置为null

【强制】优先选择utf8mb4字符集,它的兼容性最好,而且还支持emoji字符。


【推荐】json 的数据使用 json 类型存储而不是 text。MySQL 会帮我们做 json 格式校验。注意长度限制。(看业务场景)


【推荐】字段尽量设置为 NOT NULL, 为字段提供默认值。 如字符型的默认值为一个空字符串值;数值型默认值为数值 0;逻辑型的默认值为数值 0;

【推荐】考虑业务场景,选择软硬删除,必要的话,新增 delete_at,软删除。

ToDo:补 GORM 和 build Tools @刘思齐 @刘涛

注意点:

  • count(*) 会统计NULL的行, count(列名) 不会统计此列为NULL值的行

  • count(distinct col) 计算该列除 NULL 之外的不重复行数,注意 count(distinct col1, col2) 如果其中一列全为 NULL,那么即使另一列有不同的值,也返回为 0。

【推荐】遇到BLOB、TEXT字段,则尽量拆出去,再用主键做关联。超过4k大值拆出,考虑换存储方案,主从延迟风险。

【推荐】反范式设计:字段允许适当冗余,以提高查询性能。 如app表中的应用名称/应用id等唯一键,可以在别的业务表中均存储一份,避免使用 join。

【推荐】时间类型采用为 timestamp 数据类型,因为 datetime 占用 8 字节,timestamp 仅占用4字节,范围为 1970-01-01 00:00:012038-01-01 00:00:00


【参考】合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检索速度。

类型(同义词) 存储长度(BYTES) 最小值(SIGNED/UNSIGNED) 最大值(SIGNED/UNSIGNED)
整型数字
TINYINT 1 -128/0 127/255
SMALLINT 2 -32,768/0 32767/65,535
MEDIUMINT 3 -8,388,608/0 8388607/16,777,215/
INT(INTEGER) 4 -2,14,7483,648/0 2147483647/4,294,967,295/
BIGINT 8 -2^63/0 263-1/264-1
时间类型
DATETIME 8 1001-01-01 00:00:00 9999-12-31 23:59:59
DATE 3 1001-01-01 9999-12-31
TIME 3 00:00:00 23:59:59
YEAR 1 1001 9999
TIMESTAMP 4 1970-01-01 00:00:00 2038-01-01 00:00:00

索引规范

【强制】表写多读少建议索引数不超过5个。表读多写少索引数不超过10个

【强制】业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引。

【强制】建议不使用 join。如果一定要使用,最多两个表 join。需要 join 的字段,数据类型必须绝对一致;多表关联查询时, 保证被关联的字段需要有索引。

【强制】在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据 实际文本区分度决定索引长度即可。 说明:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分度会高达 90%以上。

【强制】在建立索引时,多考虑建立联合索引,并把区分度最高的字段放在最前面。

【强制】模糊查询仅允许右模糊 即“xxx%”,如果需要请走ES来解决。

【强制】不要用外键,一切外键概念在应用层解决。


【推荐】利用覆盖索引来进行查询操作,避免回表。即 select b from tableA where a = 1

【推荐】如果选择性超过 20%(区分度低于20%),那么全表扫描比使用索引性能更优,即没有设置索引的必要。

【推荐】防止因字段类型不同造成的隐式转换,导致索引失效。

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

【推荐】不要对频繁更新字段加索引


【参考】创建索引时避免有如下极端误解

  • 错误一:宁滥勿缺。认为一个查询就需要建一个索引。

  • 错误二:宁缺勿滥。认为索引会消耗空间、严重拖慢更新和新增速度。

  • 错误三:抵制惟一索引。认为业务的惟一性一律需要在应用层通过“先查后插”方式解决。

使用规范

【强制】用Explain来做SQL 性能优化,type 至少要达到 range 级别,要求是 ref 级别,如果可以是 consts 最好

描述
system The table has only one row (= system table). This is a special case of the const join type.
const The table has at most one matching row, which is read at the start of the query. Because there is only one row, values from the column in this row can be regarded as constants by the rest of the optimizer. const tables are very fast because they are read only once.
eq_ref One row is read from this table for each combination of rows from the previous tables. Other than the system and const types, this is the best possible join type. It is used when all parts of an index are used by the join and the index is a PRIMARY KEY or UNIQUE NOT NULL index.
ref All rows with matching index values are read from this table for each combination of rows from the previous tables. ref is used if the join uses only a leftmost prefix of the key or if the key is not a PRIMARY KEY or UNIQUE index (in other words, if the join cannot select a single row based on the key value). If the key that is used matches only a few rows, this is a good join type.
fulltext The join is performed using a FULLTEXT index.
ref_or_null This join type is like ref, but with the addition that MySQL does an extra search for rows that contain NULL values. This join type optimization is used most often in resolving subqueries. In the following examples, MySQL can use a ref_or_null join to process ref_table:
index_merge This join type indicates that the Index Merge optimization is used. In this case, the key column in the output row contains a list of indexes used, and key_len contains a list of the longest key parts for the indexes used
unique_subquery This type replaces eq_ref for some IN subqueries of the following form:
index_subquery This join type is similar to unique_subquery. It replaces IN subqueries, but it works for nonunique indexes in subqueries of the following form
range Only rows that are in a given range are retrieved, using an index to select the rows. The key column in the output row indicates which index is used. The key_len contains the longest key part that was used. The ref column is NULL for this type.
index The index join type is the same as ALL, except that the index tree is scanned. This occurs two ways:
- If the index is a covering index for the queries and can be used to satisfy all data required from the table, only the index tree is scanned. In this case, the Extra column says Using index. An index-only scan usually is faster than ALL because the size of the index usually is smaller than the table data.
-A full table scan is performed using reads from the index to look up data rows in index order. Uses index does not appear in the Extra column.
-MySQL can use this join type when the query uses only columns that are part of a single index.
ALL A full table scan is done for each combination of rows from the previous tables. This is normally not good if the table is the first table not marked const, and usually very bad in all other cases. Normally, you can avoid ALL by adding indexes that enable row retrieval from the table based on constant values or column values from earlier tables.

【强制】不要使用 count(列名)或 count(常量)来替代 count(),count()是 SQL92 定义的 标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。

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

【强制】连表查询的情况下,要确保关联条件的数据类型一致,避免嵌套

【强制】使用 ISNULL()来判断是否为 NULL 值。 说明:NULL 与任何值的直接比较都为 NULL。

  • NULL<>NULL的返回结果是NULL,而不是false。

  • NULL=NULL的返回结果是NULL,而不是true。

  • NULL<>1的返回结果是NULL,而不是true。

【强制】查询时不要对索引列做计算/使用函数。避免索引列的类型转换以及字符串编码转换。

【强制】更新数据超过1000条的update,delete和insert语句,需要改成分批量多次更新来进行

【强制】禁止使用存储过程,视图,触发器,event等高级特性

【强制】in子句中的值不要超过500个

【强制】提RDS DML工单时,update or delete 的长度确定时,加上 limit <行数>。这样就算提的工单 DML SQL写错了,错误造成的影响也可控。(降低工单造成的事故风险)

【强制】提工单的时候备注背景写一下。


【推荐】不建议使用子查询,建议将子查询 SQL 拆开结合程序多次查询。

【推荐】不要对索引字段使用负向查询,比如not in,not like

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,233评论 6 495
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,357评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,831评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,313评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,417评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,470评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,482评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,265评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,708评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,997评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,176评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,503评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,150评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,391评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,034评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,063评论 2 352

推荐阅读更多精彩内容

  • MySQL索引原理 索引目的 索引的目的在于提高查询效率,可以类比字典,如果要查“mysql”这个单词,我们肯定需...
    cutieagain阅读 340评论 0 0
  • Mysql相关 Mysql并发控制-锁 共享锁 共享锁也称为读锁,读锁允许多个连接可以同一时刻并发的读取同一资源,...
    万福来阅读 235评论 0 0
  • 前言 关于前面讲过的知识点我就不再赘述了,还没看过的朋友可以进入我的首页进行查阅(前言部分附赠飞机票)。这篇文章将...
    6曦轩阅读 552评论 0 0
  • M ysql索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存。如果没有索引,执行查询...
    脆皮鸡大虾阅读 204评论 0 0
  • 1、几种主要的数据库引擎的区别 MyISAM读取操作速度很快,而且不占用大量的内存和存储资源,但是不支持事务和外键...
    小胖六阅读 514评论 1 2