【转】数据库军规

  做过一些数据库优化,但是很多小伙伴再设计数据库的时候都会有或多或少的问题,自己曾经也有过类似的问题。从网上看到一篇58沈剑老师的文章,深深的感觉沈剑老师的这篇文章还是比较接地气的,转载分享一下。还是那句话,具体问题要具体分析。

数据库30条军规解读

(1)必须使用InnoDB存储引擎

解读:支持事务、行级锁、并发性能更好、CPU及内存缓存页优化使得资源利用率更高

(2)必须使用UTF8字符集

解读:万国码,无需转码,无乱码风险,节省空间

(3)数据表、数据字段必须加入中文注释

解读:N年后谁tm知道这个r1,r2,r3字段是干嘛的

(4)禁止使用存储过程、视图、触发器、Event

解读:高并发大数据的互联网业务,架构设计思路是“解放数据库CPU,将计算转移到服务层”,并发量大的情况下,这些功能很可能将数据库拖死,业务逻辑放到服务层具备更好的扩展性,能够轻易实现“增机器就加性能”。数据库擅长存储与索引,CPU计算还是上移吧

(5)禁止存储大文件或者大照片

解读:为何要让数据库做它不擅长的事情?大文件和照片存储在文件系统,数据库里存URI多好

(6)只允许使用内网域名,而不是ip连接数据库

(7)线上环境、开发环境、测试环境数据库内网域名遵循命名规范

业务名称:xxx

线上环境:dj.xxx.db

开发环境:dj.xxx.rdb

测试环境:dj.xxx.tdb

从库在名称后加-s标识,备库在名称后加-ss标识

线上从库:dj.xxx-s.db

线上备库:dj.xxx-sss.db

(8)库名、表名、字段名:小写,下划线风格,不超过32个字符,必须见名知意,禁止拼音英文混用

(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、<、<>、!=、not in这些操作符号。如:where name!=’shenjian’,如果存在name为null值的记录,查询结果就不会包含name为null值的记录

(15)禁止使用TEXT、BLOB类型

解读:会浪费更多的磁盘和内存空间,非必要的大量的大字段查询会淘汰掉热数据,导致内存命中率急剧降低,影响数据库性能

(16)禁止使用小数存储货币

解读:使用整数吧,小数容易导致钱对不上

(17)必须使用varchar(20)存储手机号

解读:

a)涉及到区号或者国家代号,可能出现+-()

b)手机号会去做数学运算么?

c)varchar可以支持模糊查询,例如:like“138%”

(18)禁止使用ENUM,可使用TINYINT代替

解读:

a)增加新的ENUM值要做DDL操作

b)ENUM的内部实际存储就是整数,你以为自己定义的是字符串?

(19)单表索引建议控制在5个以内

(20)单索引字段数不允许超过5个

解读:字段超过5个时,实际已经起不到有效过滤数据的作用了

(21)禁止在更新十分频繁、区分度不高的属性上建立索引

解读:

a)更新会变更B+树,更新频繁的字段建立索引会大大降低数据库性能

b)“性别”这种区分度不大的属性,建立索引是没有什么意义的,不能有效过滤数据,性能与全表扫描类似

(22)建立组合索引,必须把区分度高的字段放在前面

解读:能够更加有效的过滤数据

(23)禁止使用SELECT *,只获取必要的字段,需要显示说明列属性

解读:

a)读取不需要的列会增加CPU、IO、NET消耗

b)不能有效的利用覆盖索引

c)使用SELECT *容易在增加或者删除字段后出现程序BUG

(24)禁止使用INSERT INTO t_xxx VALUES(xxx),必须显示指定插入的列属性

解读:容易在增加或者删除字段后出现程序BUG

(25)禁止使用属性隐式转换

解读:SELECT uid FROM t_user WHERE phone=13812345678 会导致全表扫描,而不能命中phone索引,猜猜为什么?(这个线上问题不止出现过一次)

(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异常,并有相应处理

 

总结:大数据量高并发的互联网业务,极大影响数据库性能的都不让用,不让用哟。

补充说明:

1.新库默认使用utf8mb4字符集(如果没有特殊表情图片存储之类的,还是建议使用utf8)

utf8mb4是utf8的超集,emoji表情以及部分不常见汉字在utf8下会表现为乱码,故需要升级至utf8mb4。

默认使用这个字符集的原因是:“标准,万国码,无需转码,无乱码风险”,并不“节省空间”。

一个潜在坑:阿里云上RDS服务如果要从utf8升级为utf8mb4,需要重启实例,所以58到家并没有把所有的数据库升级成这个字符集,而是“新库默认使用utf8mb4字符集”。

自搭的Mysql可以完成在线转换,而不需要重启数据库实例。

2.数据表、数据字段必须加入中文注释

这一点应该没有疑问。

不过也有朋友提出,加入注释会方便黑客,建议“注释写在文档里,文档和数据库同步更新”。这个建议根据经验来说是不太靠谱的:

(1)不能怕bug就不写代码,怕黑客就不写注释,对吧?

(2)文档同步更新也不太现实,还是把注释写好,代码可读性做好更可行,互联网公司的文档管理?呆过互联网公司的同学估计都清楚。

3.禁止使用存储过程、视图、触发器、Event

4.禁止使用外键,如果有外键完整性约束,需要应用程序控制

5.禁止大表使用JOIN查询,禁止大表使用子查询(这点表示赞同,也是网站访问量大了之后,慢慢升级才发现,这点也许很重要)

很多网友提出,这些军规不合理,完全做到不可能

如原文所述,58到家数据库30条军规的背景是“并发量大、数据量大的互联网业务”,这类业务架构设计的重点往往是吞吐量,性能优先(和钱相关的少部分业务是一致性优先),对数据库性能影响较大的数据库特性较少使用。这类场景的架构方向是“解放数据库CPU,把复杂逻辑计算放到服务层”,服务层具备更好的扩展性,容易实现“增机器就扩充性能”,数据库擅长存储与索引,勿让数据库背负过重的任务。

关于这个点,任何事情都没有百分之百,但58到家的数据库使用确实没有存储过程、视图、触发器、外键、用户自定义函数,针对业务特性设计架构,等单库吞吐量到了几千上万,就明白这些军规的重要性啦。

6.只允许使用内网域名,而不是ip连接数据库

这一点应该也没有疑问。

不只是数据库,缓存(memcache、redis)的连接,服务(service)的连接都必须使用内网域名,机器迁移/平滑升级/运维管理…太多太多的好处,如果朋友你还是采用ip直连的,赶紧升级到内网域名吧。

 

7.禁止使用小数存储国币

有朋友问存储前乘以100,取出后除以100是否可行,个人建议“尽量少的使用除法”。

曾经踩过这样的坑,100元分3天摊销,每天摊销100/3元,结果得到3个33.33。后来实施对账系统,始终有几分钱对不齐,郁闷了很久(不是几分钱的事,是业务方质疑的眼神让研发很不爽),最后发现是除法惹的祸。

解决方案:使用“分”作为单位,这样数据库里就是整数了。

案例:SELECT uid FROM t_user WHERE phone=13812345678 会导致全表扫描,而不能命中phone索引

这个坑大家没踩过么?

phone是varchar类型,SQL语句带入的是整形,故不会命中索引,加个引号就好了:

SELECT uid FROM t_user WHERE phone=’13812345678’

8.禁止使用负向查询NOT、!=、<>、!<、!>、NOT IN、NOT LIKE等,会导致全表扫描

此军规争议比较大,部分网友反馈不这么做很多业务实现不了,稍微解释一下:

一般来说,WHERE过滤条件不会只带这么一个“负向查询条件”,还会有其他过滤条件,举个例子:查询沈剑已完成订单之外的订单(好拗口):

  SELECT oid FROM t_order WHERE uid=123 AND status != 1;

订单表5000w数据,但uid=123就会迅速的将数据量过滤到很少的级别(uid建立了索引),此时再接上一个负向的查询条件就无所谓了,扫描的行数本身就会很少。

但如果要查询所有已完成订单之外的订单:

SELECT oid FROM t_order WHERE status != 1;

这就挂了,立马CPU100%,status索引会失效,负向查询导致全表扫描。

最后,还有一个行为规范的军规:

(31)禁止使用应用程序配置文件内的帐号手工访问线上数据库

(32)禁止非DBA对线上数据库进行写操作,修改线上数据需要提交工单,由DBA执行,提交的SQL语句必须经过测试

(33)分配非DBA以只读帐号,必须通过VPN+跳板机访问授权的从库

(34)开发、测试、线上环境隔离

为什么要制定行为规范的军规呢,大伙的公司是不是有这样的情况:

任何研发、测试都有连接线上数据库的帐号?

是不是经常有这类误操作?

(1)本来只想update一条记录,where条件搞错,update了全部的记录

(2)本来只想delete几行记录,结果删多了,四下无人,再insert回去

(3)以为drop的是测试库,结果把线上库drop掉了

(4)以为操作的是分库x,结果SecureCRT开窗口太多,操作成了分库y

(5)写错配置文件,压力测试压到线上库了,生成了N多脏数据

无数的事情,结果就是打电话给DBA,让他们帮忙擦屁股。

所谓的“业务灵活性”都是扯淡,为什么要有行为规范?不让你带刀,不是限制你,而是保护你的安全。要相信DBA是专业的,让专业的人干专业的事情。别把DBA看做你的对立面,多和他们沟通业务场景,沟通请求读写比,沟通访问模式,他们真的能帮助到你,这是我带DBA团队的一些感触。

【原文链接】http://mp.weixin.qq.com/s/Yjh_fPgrjuhhOZyVtRQ-SA

时间: 2024-09-29 07:09:35

【转】数据库军规的相关文章

MySQL数据库军规

一.数据库的总体架构我们首先来看MySQL数据的总体架构如下:这是一张非常经典的MySQL的系统架构图,通过这个图可以看出MySQL各个部分的功能.当客户端连接数据库的时候,首先面对的是连接池,用于管理用户的连接,并会做一定的认证和鉴权.连接了数据库之后,客户端会发送SQL语句,而SQL接口这个模块就是来接受用户的SQL语句的.SQL语句往往需要符合严格的语法规则,因而要有语法解析器对语句进行语法解析,解析语法的原理如同编译原理中的学到的那样,从语句变成语法树.对于用户属于的查询可以进行优化,从

宜信的105条数据库军规

作为一家金融科技企业,宜信的大量业务都依赖于数据库.如何提高公司整体数据库应用水平,是对DBA的一大挑战,也非常具有现实意义.笔者在宜信的多年工作中,与团队一起总结整理了针对传统关系型数据库的使用规则,并借助自研的数据库审核平台落地,借此帮助研发团队评估数据库开发质量,达到尽早发现问题.解决问题之目的.下图正是这一系统的简单原理图. 如上图所示,针对规则部分又可细分为如下分类(部分).简单描述如下,后面将逐一详细说明. 一.Oracle规则(对象) 1.1 表.分区 [规则1] 规则说明:超过指

微服务化的数据库设计与读写分离

数据库永远是应用最关键的一环,同时越到高并发阶段,数据库往往成为瓶颈,如果数据库表和索引不在一开始就进行良好的设计,则后期数据库横向扩展,分库分表都会遇到困难. 对于互联网公司来讲,一般都会使用Mysql数据库. 一.数据库的总体架构 我们首先来看Mysql数据的总体架构如下: 这是一张非常经典的Mysql的系统架构图,通过这个图可以看出Mysql各个部分的功能. 当客户端连接数据库的时候,首先面对的是连接池,用于管理用户的连接,并会做一定的认证和鉴权. 连接了数据库之后,客户端会发送SQL语句

用尽洪荒之力整理的Mysql数据库32条军规

今天上午吐血整理了Oracle SQL性能优化的40条军规,其中很多规则也是适用于Mysql的,结果今晚发现这一篇文章——用尽洪荒之力整理的Mysql数据库32条军规,和我的竟有异曲同工之妙,当然不同的是这是由具有12年Java开发经验的老鸟写的,其见解和认识肯定比我的更加深刻,感谢前辈,现全文转载如下: --------------------------------------------------------------split line------------------------

58到家数据库30条军规解读

此篇文章来源于微信公众号[架构师之路],为了帮助记忆,现在抄写与此,如有侵权,告知立刻删除,谢谢! 军规使用场景:并发量大.数据量大的互联网业务 基础规范 必须使用 InnoDB 存储引擎:支持事务.行级锁.并发性能更好.CPU及内存缓存页优化使得资源利用率更高 必须使用 UTF8 字符集:万国码.无需转码.五乱码风险,节省空间 数据表.数据字段必须加入 中文注释 :好记忆不如烂笔头 禁止 使用存储过程.视图.触发器.Event:高并发大数据的互联网业务,架构设计思路是"解放数据库CPU,将计算

58到家数据库30条军规

军规适用场景:并发量大.数据量大的互联网业务 军规:介绍内容 解读:讲解原因,解读比军规更重要 一.基础规范 (1)必须使用InnoDB存储引擎 解读:支持事务.行级锁.并发性能更好.CPU及内存缓存页优化使得资源利用率更高 (2)必须使用UTF8字符集 解读:万国码,无需转码,无乱码风险,节省空间 和DBA负责人确认后,纠正为"新库默认使用utf8mb4字符集". 这点感谢网友的提醒,utf8mb4是utf8的超集,emoji表情以及部分不常见汉字在utf8下会表现为乱码,故需要升级

【转】58到家数据库30条军规解读

一.基础规范 (1)必须使用InnoDB存储引擎 解读:支持事务.行级锁.并发性能更好.CPU及内存缓存页优化使得资源利用率更高 (2)必须使用UTF8字符集 解读:万国码,无需转码,无乱码风险,节省空间 (3)数据表.数据字段必须加入中文注释 解读:N年后谁tm知道这个r1,r2,r3字段是干嘛的 (4)禁止使用存储过程.视图.触发器.Event 解读:高并发大数据的互联网业务,架构设计思路是“解放数据库CPU,将计算转移到服务层”,并发量大的情况下,这些功能很可能将数据库拖死,业务逻辑放到服

赶集网mysql开发36条军规

写在前面的话: 总是在灾难发生后,才想起容灾的重要性: 总是在吃过亏后,才记得曾经有人提醒过. (一)核心军规 (1)不在数据库做运算 cpu计算务必移至业务层: (2)控制单表数据量 int型不超过1000w,含char则不超过500w: 合理分表: 限制单库表数量在300以内: (3)控制列数量 字段少而精,字段数建议在20以内: (4)平衡范式与冗余 效率优先: 往往牺牲范式: (5)拒绝3B 拒绝大sql语句:big sql 拒绝大事物:big transaction 拒绝大批量:big

雅虎的卓越性能团队已经确定了23个军规

1. 减少HTTP请求次数 合并图片.CSS.JS,改进首次访问用户等待时间. 2. 使用CDN 就近缓存==>智能路由==>负载均衡==>WSA全站动态加速 3. 避免空的src和href 当link标签的href属性为空.script标签的src属性为空的时候,浏览器渲染的时候会把当前页面的URL作为它们的属性值,从而把页面的内容加载进来作为它们的值. 4. 为文件头指定Expires 使内容具有缓存性.避免了接下来的页面访问中不必要的HTTP请求. 5. 使用gzip压缩内容 压缩