MYSQL开发规范

(一)建表规约

1.【强制】在编写建表语句时,需同时考虑回滚、以及必要的初始化语句;生产环境变更表或数据时须提供变更和回滚sql文件。

      说明: 以"项目名_版本号_Create.DDL"、"项目名_版本号_RollBack.DDL、"项目名_版本号_InitData.DML",

                  分别表示创建、回滚、初始化数据的sql文件放在项目工程的对应文件夹中。

2.【强制】数据库版本统一为MySQL5.6,引擎统一使用InnoDB。

3.【强制】库名、表名、字段命名,必须使用小写字母或数字组成,库名应与应用名称一致、表或字段名以英文单词加"_"

                 表示其用途/目标/意义来命名,表名、字段名不超过32个字符、表字段数量不超过35个。

                 正例:poseidon(库名)、send_task(表名),send_task_logs_201710(表名)、user_login_name(字段名)

4.【强制】主键索引名为 pk_字段名、唯一索引名为 uk_字段名、普通索引名则为 idx_字段名,索引数量不超过5个。

      说明:pk_ 即 primary key;uk_ 即 unique key;idx_ 即 index 的简称

5.【强制】表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint( 1 表示是,0 表示否)。

      说明:任何字段如果为非负数,必须是 unsigned。

      正例:表达逻辑删除的字段名 is_deleted,1 表示删除,0 表示未删除。

6.【参考】业务数据需要进行简单的归类,但相对要支持灵活变化,应使用数据字典表或通过统一服务的形式获取,

                 禁止通过distinct语句在业务数据表去重获取,禁止将归类写死在业务处理类和方法中。

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

     说明:设计时尽量使用少的空间存储字段,如能用int的就不用char或者varchar、能用tinyint的就不用int 、

      能用varchar(20)的就不用varchar(255)。

8.【推荐】关于char、varchar、text应根据是否定长、最大支持长度、效率等因素合理选择类型,建议为:

              1) 经常变化的字段用varchar

              2) 知道固定长度的用char

              3) 尽量用varchar

              4) 超过255字节的只能用varchar或者text

              5) 能用varchar的地方不用text

              6) 如超长(如5000)定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段执引效率。

9.【禁止】禁用保留字,如 desc、range、match、delayed 等,请参考 MySQL 官方保留字

10.【禁止】小数类型为 decimal,禁止使用 float 和 double。

        说明:float 和 double 在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不

                   正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储。

11.【强制】表必备三字段:id, create_time, modified_time。

         说明:其中 id 必为主键。create_time表示主动创建, modified_time过去分词表示被动更新。

12.【强制】时间格式统一用yyyy-MM-dd HH:mm:ss.fff,精准到毫秒;存储、传输统一用北京时间,

          如有其它时区时间(如下单、付款等时间)保留原始时间、转换的原则为谁用谁转换。

13.【推荐】字段允许适当冗余,以提高查询性能,但必须考虑数据一致。冗余字段应遵循:

                   1)不是频繁修改的字段。

                   2)不是 varchar 超长字段,更不能是 text 字段。

       正例:商品类目名称使用频率高,字段长度短,名称基本一成不变,可在相关联的表中冗余存

                  储类目名称,避免关联查询。

14.【推荐】单表行数超过 100 万行或者单表容量超过 1GB,才推荐进行分库分表分区。

         说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表分区。

15.【强制】表、字段注释(COMMENT)需遵守以下注释约束,如有修改字段含义或对字段表示的状态追加时,

                    需要及时更新字段注释以及《数据库设计说明书》,注释格式参考:

                  1)  表/视图注释格式为:用途|负责人|创建日期 ,如:记录用户身份证号码|张三|2017-12-28

                  2)  字段注释格式为:用途|说明 , 如:记录用户性别|1男,2女,3未知(李四 2017-12-28 新增)

                  3)  关联字段来源需要说明,来自哪张表的那个字段,如:取自eload_user.user_id

16.【禁止】禁止定义枚举类型的表;因为在使用canal内核的产品无法拉到数据

17.【强制】字符类型的存储禁止用null,用""代替;如有将字段和值拼接成字符串存储的需要,统一先转json格式存储。

(二)索引规范

1.【推荐】ID、关联字段、业务外键、create_time 字段推荐建索引,在选择性高的字段创建索引,注意组合索引的顺序,

                 利用索引的最左原则,使用复合索引,而不是添加新的索引、避免冗余索引。

                 反例:idx_a_b_c(a,b,c)、idx_a(a)、idx_a_b(a,b)

2.【推荐】业务上具有唯一特性的字段,且具有强唯一性要求。推荐建成唯一索引。

      说明: 不要以为唯一索引影响了 insert 速度,这个速度损耗可以忽略,但提高查找速度是明显的;

                  另外,即使在应用层做了非常完善的校验控制,只要没有唯一索引,根据墨菲定律,必然有脏数据产生。

      示例:如身份证号码,在业务层面已经做了唯一性检查,但在表设计时还是要加唯一索引约束。

3.【推荐】原则上超过三个表禁止 join,如超过三张以上表join须集体评审讨论通过。需要 join 的字段,

                 数据类型必须绝对一致;多表关联查询时,保证被关联的字段需要有索引。

      说明:即使双表 join 也要注意表索引、SQL 性能。

4.【推荐】在 varchar 字段上建立索引时,建议指定索引长度,没必要对全字段建立索引,根据

                 实际文本区分度决定索引长度即可。

       说明:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分

                度会高达 90%以上,可以使用 count(distinct left(列名, 索引长度))/count(*)的区分度来确定。

       示例:如varchar(1024),索引长度为36时区分度就有 90%以上,就没必须建立1024长度的索引。

5.【强制】页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。

       说明:索引文件具有 B-Tree 的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引。

6.【推荐】如果有 order by 的场景,请注意利用索引的有序性。order by 最后的字段是组合

                 索引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能。

                 正例:where a=? and b=? order by c; 索引:a_b_c

                 反例:索引中有范围查找,那么索引有序性无法利用,如:WHERE a>10 ORDER BY b; 索引a_b 无法排序。

7. 【推荐】利用覆盖索引来进行查询操作,避免回表。

       说明:如果索引包含所有满足查询需要的数据的索引成为覆盖索引(Covering Index),也就是平时所说的不需要回表操作

       说明:使用explain,可以通过输出的extra列来判断,对于一个索引覆盖查询,显示为using index,

                  MySQL查询优化器在执行查询前会决定是否有索引覆盖查询

8. 【推荐】利用延迟关联或者子查询优化超多分页场景。

      说明:MySQL 并不是跳过 offset 行,而是取 offset+N 行,然后返回放弃前 offset 行,返回

                 N 行,当 offset 特别大的时候,效率会非常的低下。

      正例:通过使用覆盖索引查询返回需要的主键,再根据主键关联原表获得需要的数据。

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

      说明: 以下列出的12种级别,等级依次降低:

      1) system:系统表,表只有一行记录。这是const表连接类型的一个特例;

      2) const: 表中最多只有一行匹配的记录。读常量,由于只有一行记录,优化程序里该行记录的字段值可以被当作是一

          个常量,仅在查询开始时读取一次。当PRIMARY KEY或UNIQUE索引与常量进行比较时会显示const,速度非常快;

      3) eq_ref:类似const,const比较的是常量,eq_ref是同另一张表中的字段关联比较,这是最好的连接类型,

                eq_ref出现在PRIMARY KEY或UNIQUE类型索引进行”=”做比较时检索字段,

                比较的值可以是固定值或者是表达式,表达示中可以使用表里的字段;

      4) ref:查询时的索引类型不是PRIMARY KEY或UNIQUE类型索引导致匹配到的行有多个,或者仅能用到索引的

                左前缀而非全部时的访问类型,ref可被用于基于索引字段进行 - 或 <=> 操作;

      5) ref_or_null:与ref的唯一区别就是在使用索引引用的查询之外再增加一个空值的查询。这种连接类型类似ref,

                不同的是MySQL会在检索的时候额外的搜索包含NULL值的记录,它经常用于子查询。

      6) index_merge:查询中同时使用两个(或更多)索引,然后对索引结果进行合并(merge),再读取表数据;

      7) unique_subquery: 子查询中的返回结果字段组合是主键或唯一约束。用于in比较操作符中的子查询锦绣谷的

               “键值唯一”的访问类型场景中,如value in (select primary_key from table where x = x)

      8) index_subquery:子查询中的返回结果字段组合是一个索引(或索引组合),但不是一个主键或唯一索引,

                 这种连接类型类似unique_subquery。它用子查询来代替IN,不过它用于在子查询中没有唯一索引的情况下。

      9) range:索引范围扫描 。只有在给定范围的记录才会被取出来,利用索引来取得一条记录,

                 常见于between、<、>等的查询

     10) index:全索引扫描 。连接类型跟ALL一样,不同的是它只扫描索引树。它通常会比ALL快点

                 因为索引文件通常比数据文件小。MySQL在查询的字段只是单独的索引的一部分的情况下使用这种连接类型;

     11) fulltext:用于full text索引中用纯文本匹配的方法来检索记录;

     12) all:全表扫描。

10. 【强制】建组合索引的时候,区分度最高的在最左边。

         正例:如果 where a=? and b=? ,a 列的几乎接近于唯一值,那么只需要单建 idx_a 索引即可。

         说明:存在非等号和等号混合判断条件时,在建索引时,请把等号条件的列前置。如:where a>? 

                   and b=? 那么即使 a 的区分度更高,也必须把 b 放在索引的最前列。

11. 【禁止】以下情况不走索引,在编写sql或建索引时需慎重考虑:

                 1) 条件字段选择性弱,查出的结果集较大,不走索引;

                 2) where条件等号两边字段类型不同,不走索引;

                 3) 优化器分析的统计信息陈旧也可能导致不走索引;

                 4) 索引字段 is null 不走索引;

                 5) 对于count(*)当索引字段有not null约束时走索引,否则不走索引;

                 6) like 后面的字符当首位为通配符时不走索引;

                 7) 使用不等于操作符如:<>、!= 等不走索引;

                 8) 索引字段前加了函数或参加了运算不走索引;

(三)SQL语句

1.【强制】重要的业务数据、配置数据等在做删除处理时,推荐使用删除标记做逻辑删除、不使用delete做物理删除;

                 禁止update和delete语句后面没有带where条件。

2.【推荐】复杂的业务逻辑的判断或操作,建议在业务代码中分步骤拆分编写,如果一条sql写完,

                 会造成该sql语句过于复杂庞大,可读性可维护性下变差,性能一般也不会太高。

3.【强制】sql语句应按照业务模块等分文件统一写在xml或公用类中,禁止sql语句与业务代码混写在一起。

4.【禁用】"<>"、"!="、"not in"、"exsits"和"not exists"等反逻辑运算符原则上禁用。

      说明:"<>"、"!="、"not in"可用"="和"in"代替;"exsits"、"not exists"可用"等连接"和"外连接"

5.【推荐】关于or、in、union all运算符的选择,建议同一字段,将or改写为in,不同字段,将or改为union all

6.【强制】sql语句中的where子句中的每个条件的操作符两边类型应该相等,禁止潜在的数据类型做转换。

7.【强制】不要使用 count(列名)或 count(常量)来替代 count(*),count(*)是 SQL92 定义的

                 标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。

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

8.【强制】count(distinct col) 计算该列除 NULL 之外的不重复行数,注意 count(distinct

                 col1, col2) 如果其中一列全为 NULL,那么即使另一列有不同的值,也返回为 0。

9.【强制】当某一列的值全是 NULL 时,count(col)的返回结果为 0,但 sum(col)的返回结果为

                 NULL,因此使用 sum()时需注意 NPE 问题。

      正例:可以使用如下方式来避免 sum 的 NPE 问题:SELECT IF(ISNULL(SUM(g)),0,SUM(g))  FROM table;

10. 【强制】使用 ISNULL()来判断是否为 NULL 值。

        说明:  NULL 与任何值的直接比较都为 NULL。

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

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

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

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

12.【禁止】不得使用外键与级联,一切外键概念必须在应用层解决。

       说明:以学生和成绩的关系为例,学生表中的 student_id是主键,那么成绩表中的 student_id

                  则为外键。如果更新学生表中的 student_id,同时触发成绩表中的 student_id 更新,即为

                  级联更新。外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻

                  塞,存在数据库更新风暴的风险;外键影响数据库的插入速度。

13.【禁止】禁止使用存储过程、触发器、游标,这些难以调试和扩展,更没有移植性。

14.【强制】数据订正(特别是删除、修改记录操作)时,要先确认,避免出现误删除,确认无误才能执行更新语句。 

        示例:如A、B两个线程都读取某条数据其中一个字段值(如1000)做加100操作,A线程将值更新为1100,

        B线程如果不加判断,结果也会更新也为1100,正确的结果值应为1200,可通过增加版本号等字段来控制。

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

16.【强制】数据库编码格式、所字符存储与表示,均以 utf-8 编码,注意字符统计函数的区别。

        说明: SELECT LENGTH("轻松工作"); 返回为 12

                    SELECT CHARACTER_LENGTH("轻松工作"); 返回为 4

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

推荐阅读更多精彩内容

  • 库表设计 库名、表名、字段名使用小写字母,”_”分割,不超过18 个字符,使用名词且见名知意. 不使用temp、o...
    迷途的华生阅读 1,011评论 0 10
  • 来源与:阿里云栖 禁止用于商业用途 ps:如果需要电子书 评论你们邮箱 我会发给你们 下面感觉还是有点乱 目录 一...
    小向资源网阅读 7,570评论 0 12
  • 一、 表设计类 强制类规范 创建表的存储引擎必须是InnoDB。 每个表必须显式的指定一个主键。 不允许使用联合主...
    xianyu阅读 386评论 0 0
  • 【同读一本书刘姣】 2016-03-09-041 -《影响力》 【原文】 “对比原理在精神物理学领域里得到了长...
    城市格调刘姣阅读 326评论 1 0
  • 我容忍你,不是因为我懦弱,而是因为我的不忍,不忍看到自己变得和你一样卑鄙,这样我会讨厌我自己。
    三文鱼蛋炒饭阅读 275评论 0 0