MySQL 建表规范 以及注意

参考 Alibaba  P3C 规范文档  git

https://github.com/alibaba/p3c/blob/master/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4Java%E5%BC%80%E5%8F%91%E6%89%8B%E5%86%8C%EF%BC%88%E8%AF%A6%E5%B0%BD%E7%89%88%EF%BC%89.pdfgithub

 

  1. 建表规范

        1).在使用判断是否的状况下,使用 is_xxx的命名,而且数据类型是unsigned tinyint(1表示为真 0表示为假)。sql

        2).全部的表的代表必须以小写字母+数字(windows不分大小写,Linux分大小写),且两个下划线中间不出现数字(错误:table1_3_system)。windows

        3).以单数形式写表名,不要使用desc,range,match,delayed等MySQL保留字段,索引名称规范为:性能优化

pk_xx 表示primary key(主键索引); uk_xx表示unique key (惟一索引);idx_xx表普通索引并发

        4).小数使用 decimal ,能够定义经常使用的如价格,工资,汇款等等。分布式

        5).长度(0-255) 且长度基本一致的使用char,长度(0-5000)不预先设置存储空间的,可使用varchar,但长度大于5000,则使用text来处理,而且新建一张表来存储,以主键绑定,避免影响其余字段索引的效率。性能

        6).一个表必备的三个字段,id,gmt_create,gmt_modified,id表主键应该是无符号的,能够是int或bigint,后面两个为datetime类型,前者表示建立时间,后者表示被动修改时间优化

        7).命名规范,通常以“业务名_功能名”,库名应当和应用名称一致。搜索引擎

        8).表是容许适当的冗余,这样提升查询速度,当数据大时,效果很明显。但也须要注意,应当是不频繁变化的字段,且不该该是varchar超长字符,更不宜是text文本。

        9).单表内容超过500W行或者存储大于2GB,才推荐分库分表,若是预计三年内达不到该值,在设计是能够不考虑分库分表。

        10).适当的字符存储长度,不但节约存储空间,节约索引存储,同时提高了检索的速度。  

            

     2.索引

        1).业务上具备惟一特性的字段,便是是组合也应当建成惟一索引。(不要觉得惟一索引影响insert的速度,其实能够忽略,与之相比带来的查询速度是很是大的,另外,在应用层便是是作了数据的校验,可是只要是没有惟一的索引,根据墨菲定律,必然产生脏数据。)

        2).超过三个表禁止使用join。须要使用join的须要注意索引与sql性能,同时数据类型须要一致。多表关联查询时,须要保证被关联的字段设置了索引。

        3).为varchar设置索引须要指定其长度,不必对全文本进行索引创建,通常在20长度区分度在90%以上,可使用count(distinct left(列名,索引长度))/count(*)的区分度来判断。

        4).页面搜索禁用左模糊和全模糊,若是须要则使用搜索引擎。索引文件具备B-Tree的最左前缀匹配特性,若是左边未肯定则不能使用该索引。

        5).若是与有order by 的场景,请注意利用索引的有序性。order by最后的字段是组合索引的一部分,请别放到组合索引的最后,避免出现file_sort,影响查询性能。如: where a = ? b = ? order by c; 索引为:a_b_c. 当索引中有范围查找,那么没法利用有序性。如 where a > 10 order by b; 索引为 a_b.

        6).利用覆盖索引进行查询。用explain的结果,extra列会出现:using index.

        7).利用延迟关联或子查询优化超多分页场景。也就是先定位查询值,再联合查询。

如: select a.* from table1 as a ,(select id from table2  where 条件 limit 1000,100)as b where a.id =b.id

        8).SQL 性能优化目标:至少是range级别,要求是ref级别,若是能够的话应当是consts.

            consts : 只有一条匹配数据(主键或者惟一索引)

            ref: 指的是使用普通的索引查询

            range: 对索引进行范围搜索

       9). 创建的组合索引,区分度最高的查询在左边。

        若是: where a=? b=?,a列基本上能区分出惟一值,那么只须要创建a的索引就能够。

说明: 存在等号和非等号的查询状况下,在建索引的时候,请把等号的前置。如:where a =? and b =? 便是a的区分度更高,也须要把b放在前面,即uk_b_a;

     10).防止因字段类型不一样,形成隐式的转换,致使索引失效。

     11).极端

            宁滥勿缺 : 认为一个查询就须要一个索引。

            宁缺毋滥: 认为索引会消耗控件,严重拖慢更新和新增的速度

            抵制惟一索引:认为业务的惟一性一概经过应用层检查,并经过”先查后插”方式解决。

   3. SQL语句

        1). 不要使用count(列名) 或者count(1) 来替代count(*),count(*)是sql定义的用来统计的标准语法。count(* )会统计值为NULL的行,可是count(列名) 不会统计。

        2).count(distinct col) 计算该列值非NULL且非重复的行,count(distinct  col1,col2)若是第一列值为空,那么便是另外一列有不一样的值,也是返回0.

        3).须要注意的一个问题是count(*)未找到行是返回0,而sum(col)则是返回NULL,所以会出现NPE。可使用 select if(ISNULL(sum(g)),0,sum(g)) from table.

         4).ISNULL()是判断是否为NULL,null与任何值比较都是null,而不是true 或者false。

         5).当count(*)=0 时,应当结束掉后面须要分页的操做。

         6).不使用外键与级联。一切外键概念须要在应用层解决。

            以学生表和成绩表为例,学生表的student_id是主键,而成绩表中的student_id则为外键。在更新学生表时,同时须要更新成绩表,那么这是一个级联的更新。外键,级联是单机低并发,不适合分布式,并有影响数据更新,影响插入性能。

         7).不使用存储过程。

         8).数据修好时,须要先select,在删除。

         9).in尽可能不使用,若是须要使用则须要控制in后面的数量为1000个之内。