暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

DB#1 数据库避坑指南

技术夜未眠 2020-01-02
318




关注本公众号,一天一个知识点,持续精进!


碎片时间|体系学习

今天是
2020 年的第


00、引言


数据库无处不在,几乎是现在所有软件系统的标配。为此,数据库技能实乃我们程序员居家出行必备良药。总结一个可以不断增长的经验清单,让我们能够站在前人的肩膀上,大大减少掉坑场景的发生频次。


本文以MySQL数据库系统为例进行说明,其他数据库系统可对比参考。


01、避坑指南


一、基础规范


【1】必须使用InnoDB存储引擎

InnoDB存储引擎支持事务、行级锁、并发性能更好、CPU及内存缓存页优化使得资源利用率更高。

 

【2】新库默认使用utf8mb4字符集

标准,万国码,无需转码,无乱码风险。

 

【3】数据表、数据字段必须加入中文注释

注释需准确,可读性强,尽量做到见名便知义。

 

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

该规则主要适用于高并发访问、海量数据的应用场景。数据库擅长存储与索引,属于I/O操作密集型;业务逻辑属于CPU操作密集型,不建议放在数据库,这样可以减少数据库运算量,降低数据库压力;否则,在高并发、海量数据的应用场景很容易将数据库系统冲垮。


【5】禁止存储大容量的文件或二进制多媒体数据

将大容量的文件和二进制多媒体数据(如图片、音频、视频等)存储在文件系统中,数据库里可存放相应的大容量文件/数据的URI。

 

二、命名规范


【6】只允许使用内网域名,而不是IP连接数据库。

如果对应IP的数据库服务器发生宕机,只需要修改DNS的配置即可,而不需要修改程序的源代码,这对运维或运行环境发生改变的时候都会带来极大的方便。除了数据库之外,缓存(memcache、redis)的连接,服务(service)的连接都必须使用内网域名。


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

比如:业务名称:abc

线上环境:com.abc.db

开发环境:com.abc.rdb

测试环境:com.abc.tdb

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

线上从库:com.abc-s.db

线上备库:com.abc-sss.db

 

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

 

【9】表名t_xxx,非唯一索引名idx_xxx,唯一索引名uniq_xxx

 

三、表设计规范


【10】单实例表数目必须小于500

 

【11】单表列数目必须小于30

 

【12】表必须有主键,例如自增主键

    a)主键递增,数据行写入可以提高插入性能,可以避免page分裂,减少表碎片提升空间和内存的使用

    b)主键要选择较短的数据类型, Innodb引擎普通索引都会保存主键的值,较短的数据类型可以有效的减少索引的磁盘空间,提高索引的缓存效率

 

【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 != ’User1’,如果存在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】查询条件的字段必须要有索引,可根据数据特点并非要求所有查询的字段都建立索引

没有索引的话,mysql 会全表扫描,那样会锁定整张表所有的记录;此时其他事务不能修改不能删除不能添加,进而影响数据库系统的执行性能


【20】单表索引建议控制在5个以内

 

【21】单索引字段数不允许超过5个

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

 

【22】禁止在更新十分频繁、区分度不高的属性上建立索引

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

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

 

【23】建立组合索引,必须把区分度高的字段放在前面

能够更加有效的过滤数据

 

六、SQL使用规范


【24】禁止使用SELECT *,只获取必要的字段,需要显式说明列属性

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

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

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

 

【25】禁止使用INSERT INTO t_xxx VALUES(xxx),必须显式指定插入的列属性

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

 

【26】禁止使用属性隐式转换

SELECT uid FROM t_user WHERE phone=13812345678 会导致全表扫描,而不能命中phone索引(phone字段为varchar类型,由于不存在该记录,必然需要全表扫描;修改为phone='13812345678'即可)

 

【27】禁止在WHERE条件的属性上使用函数或者表达式

SELECT uid FROM t_user WHERE from_unixtime(day)>='2018-05-19' 会导致全表扫描。正确的写法是:SELECT uid FROM t_user WHERE day>= unix_timestamp('2018-05-19 00:00:00')

 

【28】禁止单条件的负向查询,以及%开头的模糊查询

    a)负向查询条件:NOT、!=、<>、!<、!>、NOT IN、NOT LIKE等,会导致全表扫描

    b)%开头的模糊查询,会导致全表扫描。

 

【29】禁止大表使用JOIN查询,禁止大表使用子查询

会产生临时表,消耗较多内存与CPU,极大影响数据库性能

 

【30】禁止使用OR条件,必须改为IN查询

旧版本Mysql的OR查询不能利用索引机制

 

【31】应用程序必须捕获SQL异常,并有相应处理


七、行为规范


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


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


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


【35】开发、测试、线上环境隔离


八、架构设计


【36】对软件可扩展性的过度追求,促使将对象设计的时候,拆得过于离散,造成系统中有大量复杂的join语句;MySQL等数据库系统由于锁的机制,主要优势在于处理简单逻辑的查询,如果有大量复杂语言,会降低数据库性能


【37】避免对数据库的过度依赖,将一些业务逻辑也放在数据库中进行处理


【38】避免过度理想化系统的用户体验,使大量非核心业务消耗过多的资源,如对大量不需要实时更新的数据做了实时统计计算


02、小结


综上,本文以MySQL数据库系统为研究对象,结合了包括《58到家数据库30条军规》在内的互联网多篇数据库优化的技巧与经验,总结了数据库避坑指南,其目的是为了掌握20%的最常用的技能,能够解决我们在数据库方面的80%问题。本文是数据库系列的第一篇,后续我们会对数据库的事务与锁机制、设计问题等进行拆解,敬请期待。


本文延伸阅读

上文1:JVM#5  JVM内存分配的What/How

上文2: JVM#6  JVM性能监控兵器库与秘籍 — 系统环境篇

推荐1:习惯决定命运,高效程序员的习惯

推荐2:编写可读代码的艺术


近期,我和活跃在业界的一线技术老司机们共同开通了知识星球,——一个与公众号有别,但又一脉相承的技术圈、认知圈:公众号会一如既往地进行知识分享,知识星球则坚持关注解决问题与动手实践。问题很广、方法很多、思绪很快,希望我们能够在这里驻足思考、交流、沉淀、提升。


你负责认真,我们负责帮你解决问题,让改变发生;欢迎大家扫码加入我们的星球。期待 2020,在程序猿成长的道路上,共同进化!

文章转载自技术夜未眠,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论