我们程序员在面试找工作中,经常会被问到数据库设计这块的能力,因为数据库设计更多的是考察一个开发者“自上而下”的一种综合能力,这里给一个知乎上的问答很多 IT 招聘要求中需要优秀的数据库设计能力。什么是「数据库设计能力」?,大家可以了解一下。下面就介绍一下数据库设计时应该遵循的规范。
一、基础规范
(1)必须使用InnoDb存储引擎
解读:InnoDB存储引擎支持事务,行级锁,并发性能更好,CPU及内存缓存页优化使得资源利用率更高。Myisam在现在的开发中逐渐被废弃不再使用,myisam存储引擎虽然在查询操作更快,但是现在开发中各级缓存cache的加入使得即使是innodb引擎的查询操作效率也很高,而在事务处理,数据安全性方面,myisam可以说是“一无是处”。
(2)必须使用utf8字符集
解读:utf8编码可以说是各个编程语言中默认采用的字符集编码,包含世界上所有的字符和符号,不用转码操作,而且它是可变字节的,节省空间。但是在国内一些很古老的项目还是采用gbk或gb2312(捉急)。
(3)数据表(字段)写上中文注释
解读:因为很久之后可能自己都能忘了当时自己设计的字段是啥意思了
(4)禁止使用存储过程,视图,触发器,Event
解读:高并发大数据的互联网业务,架构设计思路是“解放数据库CPU,将计算转移到服务层”,并发量很大的情况下,这些功能极有可能将数据库拖死。业务逻辑放到服务层具备更好的扩展性,能够轻易实现“增机器就加性能”。数据库擅长数据的存储与索引,CPU计算还是上移吧。
(5)禁止存储大文件或者大照片
解读:虽然数据库可以存储数据量很大的二进制数据,但是这样会耗费很大的系统资源。不如把图片等静态资源存储到服务器文件系统中,数据库存储期url。
二、命名规范
(6)只允许内网域名,而不是ip连接数据库
(7)线上环境,开发环境,测试环境数据库内网域名遵循命名规范
(8)数据库名,表名,字段名全用小写字母+下划线,长度不超过32个字符,必须见名知意,禁止拼音英文混用。不建议过度设计,例如,一个goods表的自增id,商品名字,商品价格等,字段名应为id,name,price,而没必要设计成goods_id,goods_name,goods_price,这个表已经是goods表,当然会存储与商品相关的信息,再加上goods_,显得“画蛇添足”,过度设计了。
(9)表名t_xxx,非唯一索引名idx_xxx.唯一索引名uniq_xxx
三、表设计规范
(10)单个项目数据表数目必须小于500个
(11)单个数据表字段数必须小于30个
(12)表必须有主键,例如自增主键
解读:
a)主键递增,数据行写入可以提高插入性能,可以避免page分裂,减少表碎片提升空间和内存的使用
b)主键要选择较短的数据类型,Innodb引擎普通索引都会保存主键的值,较短的数据类型可以有效的减少索引的磁盘空间,提高索引的缓存效率
c)无主键的表数据删除时,在row模式的主从架构,会导致备库夯住
(13)禁止使用外键,如果有外键完整性约束,需要应用程序控制
解读:外键会导致表与表之间的耦合,update和delete操作都会涉及到相关联的表,十分影响sql的性能,甚至会导致死锁。高并发情况下容易造成数据库性能的下降,大数据高并发场景下的数据库使用以性能为优先
四、字段设计规范
(14)必须把字段定义为NOT NULL并且提供默认值
解读:
a)null的列使索引,索引统计,值比较都更加复杂,对MySQL来说更难优化
b)null这种类型MySQL内部需要进行特殊处理,增加数据库处理数据的复杂性;同等条件下,表中有较多空字段的时候,数据库的性能会下降很多
c)null值需要更多的存储空间,无论是表还是索引中每行的null的列都需要额外的空间来标识
d)对null的处理,只能采用is null或is not null,而不能采用=,in,
(15)禁止使用TEXT,blob类型
解读:会浪费更多的磁盘和内存空间,非必要的大量的大字段查询会淘汰掉热数据,导致内存命中率急剧降低,影响数据库性能。
(16)禁止使用小数存储货币
解读:几乎所有的编程语言在处理小数时,都会或多或少出现丢失精度的问题。所以,如果以分为单位时。可以把货币乘以100存进数据库
(17)必须使用varchar存储手机号(电话号)
解读:
a)涉及到区号或国家代号,可能出现+-()等字符
b)不会有人拿手机号去做数学计算的
c)varchar支持模糊查询,如:like “139%”
(18)禁止使用enum枚举类型,可以使用TINYINT代替
解读:
a)增加新的enum值就要做DDL操作
b)enum的内部实际存储就是整数,你以为自己定义的是字符串吗?
五、索引设计规范
(19)单表索引建议控制在5个以内
(20)单索引字段数不允许超过5个
解读:字段超过5个时,实际已经起不到有效过滤数据的作用了
(21)禁止在更新十分频繁、区分度不高的属性上建立索引
解读:
a)更新会变更B+树,更新频繁的字段建立索引会大大降低数据库性能
b)“性别”这种区分度不大的属性,建立索引是没有什么意义的,不能有效过滤数据,性能与全表扫描类似
(22)建立组合索引,必须把区分度高的字段放在前面
解读:能够更加有效的过滤数据
六、SQL使用规范
(23)禁止使用SELECT *,只获取必要的字段,需要显示说明列属性
解读:
a)读取不需要的列会增加CPU、IO、NET消耗
b)不能有效的利用覆盖索引
c)使用SELECT *容易在增加或者删除字段后出现程序BUG
(24)禁止使用INSERT INTO t_xxx VALUES(xxx),必须显示指定插入的列属性
解读:容易在增加或者删除字段后出现程序BUG
(25)禁止使用属性隐式转换
(26)禁止在WHERE条件的属性上使用函数或者表达式
解读:SELECT uid FROM t_user WHERE from_unixtime(day)>='2017-02-15' 会导致全表扫描
正确的写法是:SELECT uid FROM t_user WHERE day>= unix_timestamp('2017-02-15 00:00:00')
(27)禁止负向查询,以及%开头的模糊查询
解读:
a)负向查询条件:NOT、!=、<>、!<、!>、NOT IN、NOT LIKE等,会导致全表扫描
b)%开头的模糊查询,会导致全表扫描
(28)禁止大表使用JOIN查询,禁止大表使用子查询
解读:会产生临时表,消耗较多内存与CPU,极大影响数据库性能
(29)禁止使用OR条件,必须改为IN查询
解读:旧版本Mysql的OR查询是不能命中索引的,即使能命中索引,为何要让数据库耗费更多的CPU帮助实施查询优化呢?
(30)应用程序必须捕获SQL异常,并有相应处理
原文转自http://mp.weixin.qq.com/s/Yjh_fPgrjuhhOZyVtRQ-SA