您的位置:首页 > 数据库 > MySQL

MySQL 数据库设计规范 详解

2018-03-24 12:33 585 查看
1> 数据库涉及字符规范采用 26 个英文字母(区分大小写) 和 0-9 这十个自然数,加上下划线'_'组成,共 63 个字符,不能出现其他字符(注释除外)注 : 1> 以上命名都不得超过 30 个字符的系统限制,变量名的长度限制为 29(不包括标识字符@)       2> 数据对象、变量的命名都采用英文字符,禁止使用中文命名。绝对不要在对象名的字符之间留空格       3> 小心保留词,要保证字段名没有和保留词、数据库系统或者常用访问方法冲突       4> 保持字段名和类型的一致性,在命名字段并为其指定数据类型的时候一定要保证一致性。假如数据类型在一个表里是整数,那在另一个表里可就别变成字符型
2> 数据库命名规范数据库名使用小写英文以及下划线组成,比如 : my_dbsnepr备份数据库名使用正式库名加上备份时间组成,如 : dbname_20070403
3> 数据库表命名规范数据表名使用小写英文以及下划线组成,比如 :    info_user    system_destination信息类采用 : info_xxx文件类采用 : file_xxx关联类采用 : inter_xxx备份数据表名使用正式表名加上备份时间组成,如 :    info_user_20070403    system_destination_20070403
4> 字段命名规范字段名称使用单词组合完成,首字母小写,后面单词的首字母大写,最好是带表名前缀,如 web_user 表的字段 :    userId    userName如果表名过长,可以取表名的前5个字母。如果表名为多个单词组合,可以取前一个单词,外加后续其它单词的首字母作为字段名表与表之间的相关联字段要用统一名称,如 info_user 表里面的 userId 和 group 表里面的 userId 相对应业务流水号统一采用 : 表名_seq注 : 字段名前面增加表名,就不用担心在多表查询时对同名字段的冲突
表名、字段名必须使用小写字母或数字;禁止出现数字开头,禁止两个下划线中间只出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑正例 : getter_admin, task_config, level3_name反例 : GetterAdmin, taskConfig, level_3_name
表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint(1 表示是, 0 表示否) ,此规则同样适用于 odps 建表说明 : 任何字段如果为非负数,必须是 unsigned
表名不使用复数名词说明 : 表名应该仅仅表示表里面的实体内容,不应该表示实体数量,对应于 DO 类名也是单数形式,符合表达习惯
唯一索引名为 uk_字段名;普通索引名则为 idx_字段名说明 : uk_ 即 unique key;idx_ 即 index 的简称
小数类型为 decimal,禁止使用 float 和 double说明 :  float 和 double 在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储
如果存储的字符串长度几乎相等,使用 char 定长字符串类型
varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长度大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索引效率
表必备三字段 : id, gmt_create, gmt_modified说明 : 其中 id 必为主键,类型为 unsigned bigint、单表时自增、步长为 1。 gmt_create, gmt_modified 的类型均为 date_time 类型
表的命名最好是加上“业务名称_表的作用”正例: tiger_task / tiger_reader / mpp_config
库名与应用名称尽量一致
单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表说明 : 如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表
5> 外键命名规范外键名称为 FK_表名_A_表名_B_关联字段名其中表名和关联字段名如果过长,可以取表名、关联字段名的前5个字母如果表名、关联字段为多个单词组合,可以取前一个单词,外加后续其它单词的首字母作为字段名如 : FK_user_token_user_phnum;
6> 字段类型规范规则 : 用尽量少的存储空间来存数一个字段的数据    <1> 能用 int 的就不用 char 或者 varchar    <2> 能用 varchar(20) 的就不用 varchar(255)    <3> 时间戳字段尽量用 int 型,如 created:表示从'1970-01-01 08:00:00'开始的 int 秒数,采用英文单词的过去式;gmtCreated:表示 datetime 类型的时间,即形如'1980-01-01 00:00:00'的时间串,Java 中对应的类型为 Timestamp
7> 索引使用原则    <1> 逻辑主键使用唯一的成组索引,对系统键 (作为存储过程) 采用唯一的非成组索引,对任何外键列采用非成组索引。考虑数据库的空间有多大,表如何进行访问,还有这些访问是否主要用作读写    <2> 大多数数据库都索引自动创建的主键字段,但是可别忘了索引外键,它们也是经常使用的键,比如运行查询显示主表和所有关联表的某条记录就用得上    <3> 不要索引 blob/text 等字段,不要索引大型字段(有很多字符),这样作会让索引占用太多的存储空间    <4> 不要索引常用的小型表    <5> 不要为小型数据表设置任何键,假如它们经常有插入和删除操作就更别这样做,对这些插入和删除操作的索引维护可能比扫描表空间消耗更多的时间
业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引说明 : 不要以为唯一索引影响 insert 速度,这个速度损耗可以忽略,但提高查找速度是明显的;另外,即使在应用层做非常完善的校验和控制,只要没有唯一索引,根据墨菲定律,必然有脏数据产生
超过三个表禁止 join。需要 join 的字段,数据类型保持绝对一致; 多表关联查询时,保证被关联的字段需要有索引说明 : 即使双表 join 也要注意表索引、SQL 性能
在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度说明 : 索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分度会高达 90%以上,可以使用 count(distinct left(列名, 索引长度))/count(*) 的区分度来确定
页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决说明 : 索引文件具有 B-Tree 的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引
如果有 order by 的场景,请注意利用索引的有序性。 order by 最后的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能正例 : where a=? and b=? order by c; 索引 : a_b_c反例 : 索引中有范围查找,那么索引有序性无法利用,如 : WHERE a>10 ORDER BY b; 索引a_b 无法排序
先快速定位需要获取的 id 段,然后再关联 : SELECT a.* FROM 表 1 a, (select id from 表 1 where 条件 LIMIT 100000,20 ) b where a.id=b.id
建组合索引的时候,区分度最高的在最左边
创建索引时避免有如下极端误解 :1> 误认为一个查询就需要建一个索引2> 误认为索引会消耗空间、严重拖慢更新和新增速度3> 误认为唯一索引一律需要在应用层通过 "先查后插" 方式解决
不要使用 count(列名)或 count(常量)来替代 count(*),count(*)就是 SQL92 定义的标准统计行数的语法,跟数据库无关,跟 NULL 和 非NULL 无关说明 : count(*) 会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行
count(distinct col) 计算该列除 NULL 之外的不重复数量注 : count(distinct col1, col2) 如果其中一列全为 NULL,那么即使另一列有不同的值,也返回为 0
当某一列的值全是 NULL 时,count(col)的返回结果为 0,但 sum(col)的返回结果为NULL,因此使用 sum()时需注意 NPE 问题正例 : 可以使用如下方式来避免 sum 的 NPE问题 : SELECT IF(ISNULL(SUM(g)),0,SUM(g)) FROM table;
使用 ISNULL()来判断是否为 NULL 值,说明 :1> NULL<>NULL 的返回结果是 NULL, 而不是 false2> NULL=NULL 的返回结果是 NULL, 而不是 true3> NULL<>1 的返回结果是 NULL,而不是 true注 : NULL 与任何值的直接比较都为 NULL
在代码中写分页查询逻辑时,若 count 为 0 应直接返回,避免执行后面的分页语句
不得使用外键与级联,一切外键概念必须在应用层解决说明 : 学生表中的 student_id 是主键,那么成绩表中的 student_id 则为外键。如果更新学生表中的 student_id,同时触发成绩表中的 student_id 更新,则为级联更新。外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度
禁止使用存储过程,存储过程难以调试和扩展,更没有移植性
数据订正时,删除和修改记录时,要先 select,避免出现误删除,确认无误才能执行更新语句
in 操作能避免则避免,若实在避免不了,需要仔细评估 in 后边的集合元素数量,控制在 1000 个之内
如果有全球化需要,所有的字符存储与表示,均以 utf-8 编码,那么字符计数方法说明 :SELECT LENGTH("轻松工作"); 返回为 12SELECT CHARACTER_LENGTH("轻松工作"); 返回为 4如果要使用表情,那么使用 utfmb4 来进行存储,注意它与 utf-8 编码的区别
TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源少,但 TRUNCATE 无事务且不触发 trigger,有可能造成事故,故不建议在开发代码中使用此语句说明 : TRUNCATE TABLE 在功能上与不带 WHERE 子句的 DELETE 语句相同
POJO 类的 boolean 属性不能加 is,而数据库字段必须加 is_,要求在 resultMap 中进行字段与属性之间的映射说明 : 参见定义 POJO 类以及数据库字段定义规定,在 sql.xml 增加映射,是必须的
不要用 resultClass 当返回参数,即使所有类属性名与数据库字段一一对应,也需要定义; 反过来,每一个表也必然有一个与之对应说明 : 配置映射关系,使字段与 DO 类解耦,方便维护
8> SQL语句规范所有SQL关键词全部大写,比如 SELECT,UPDATE,FROM,ORDER,BY 等,表名与字段名不需要大写,如 :SELECT COUNT(*) FROM cdb_members WHERE userName='aeolus';
在表查询中,一律不要使用 * 作为查询的字段列表,需要哪些字段必须明确写明说明 : 1> 增加查询分析器解析成本  2> 增减字段容易与 resultMap 配置不一致
不要写一个大而全的数据更新接口,传入为 POJO 类,不管是不是自己的目标更新字段,都进行 update table set c1=value1,c2=value2,c3=value3; 这是不对的。执行 SQL 时,尽量不要更新无改动的字段,一是易出错; 二是效率低; 三是 binlog 增加存储
9> 内容注释存储过程,触发器,函数,视图等都应该加上内容注释,注释格式如下:-- =============================================-- Author: Tiger-- Create date: 2009-4-15-- Description: 根据信息完整度生成客户统计数据-- Update: 2009-4-30 By Tiger-- =============================================表的陌生字段应当加上简要的字段说明和内容说明
10> 其他设计技巧    <1> 避免使用触发器 : 触发器的功能通常可以用其他方式实现,在调试程序时触发器可能成为干扰,假如确实需要采用触发器,最好集中对它文档化    <2> 避免使用存储过程    <3> 使用常用英语 (或者其他任何语言) 而不要使用拼音首字母缩写    <4> 更新数据表记录时,必须同时更新记录对应的 gmt_modified 字段值为当前时间
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: