目录
概述
目的
本文档主要目的是对所有数据库对象(包括库、表、字段、索引、主键、外键、约束、表分区、触发器、存储过程等)的使用场景及使用规范,进行相关的约定,供日后应用开发、数据库设计、数据库维护提供规范性依据。
读者对象
参考文档
无。
术语定义
术语 | 解释 |
---|---|
字符集 | 字符集(Character set)是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集名称:UTF-8字符集,UTF-8-MB4字符集,ASCII字符集、GB2312字符集、BIG5字符集、 GB18030字符集、Unicode字符集等。 |
存储引擎 | 用各种不同的技术将数据存储在文件(或者内存)中的机制。每一种技术都使用不同的存储机制、索引技巧、锁定水平并且最终提供广泛的不同的功能和能力。 |
数据库特性 | 跟数据自身相关,但区别于其他类型数据库的功能或者特征。 |
范式 | 范式,特指数据库设计范式,是符合某一种级别的关系模式的集合。构造数据库必须遵循一定的规则。在关系数据库中,这种规则就是范式。关系数据库中的关系必须满足一定的要求,即满足不同的范式。 |
冗余 | 特指在数据库设计中,本不属于表实体的属性,但因性能或者其他要求,将这些属性也在本表中存储,定义为冗余。 |
索引 | 在关系数据库中,索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构。 |
前缀索引 | 在数据库设计中,特指对某个字段前部分内容建立索引,称为前缀索引。 |
联合索引 | 联合索引是由多个字段组成的索引。 |
主键 | 也称主关键字(primary key),是表中的一个或多个字段,它的值用于唯一地标识表中的某一条记录。 |
稠密度 | 特指经过索引后得到的数据占整个表数据的比值。 |
聚合函数 | SQL的基本函数,主要作用是对一组值执行计算,并返回单个值。 |
DDL | 数据定义语言(Data Definition Language),是用于描述数据库中要存储的现实世界实体的语言。 |
DML | 数据操纵语言(Data Manipulation Language, DML)是SQL语言中,负责对数据库对象运行数据访问工作的指令集。 |
负载均衡 | 负载均衡(Load Balance)其意思就是分摊到多个操作单元上进行执行,从而共同完成工作任务。 |
主从复制 | 特指实现两个数据库数据同步的一种机制。 |
数据库设计规范
数据库对象,包括库、表、字段、索引、主键、外键、约束、表分区、触发器、存储过程等,每种对象都会有它的使用场景及规范。为提高数据库的稳定性、高效性、安全性,降低数据库故障率,对数据库的对象制定以下规范,供日后应用开发、数据库设计和操作提供依据。
整体规范
注释
- 数据库所有对象必须要有注释,包括:表、字段、索引等,并且要保持最新。
字符集
- 默认使用utf8mb4字符集,无乱码风险。utf8mb4是utf8的超集,可以获得比utf8更好的兼容性。
存储引擎
-
默认使用INNODB存储引擎。 MyISAM引擎从MYSQL 5.5
版本后查询性能已经没InnoDB高,另外InnoDB的以主键为条件的查询性能是非常高的,且支持事务、行级锁、高并发性能更好、对多核CPU、大内存、SSD等硬件资源支持更好,利用率更高。 -
如需要使用基他类型的存储引擎,请在DBA的建议下使用。
不依赖数据库特性
- 降低对数据库功能的依赖,如在业务上使用了MySQL特性,且这个特性是只有MySQL存在的,对以后的数据库迁移会带来麻烦。
平衡范式与冗余
- 并非一定要遵守范式理论,适度的冗余设计,字段长度短而且频繁查询的字段可以冗余到其他表,避免表连接查询,可以极大提升查询效率。
数据库对象规范
表设计规范
控制单库表数量
- 单库表数量建议控制在500以内。
控制单表数据量
- 单表数据量建议控制在1000万以内(参考值)。表的记录数多少合适不能死搬硬套,需要根据服务器的CPU、内存、磁盘IO能力综合评估。比如服务器总内存有168G,数据库总数据文件大小100G,innodb
缓存池设置为120G,这个时候即便大表有3000万条,也可以全部加载到内存中,性能上完全不会有磁盘IO压力。根据经验值一般热数据占数据总量的10%左右,热数据都能缓存到内存中性能上就不会有磁盘IO压力。
控制单表字段数量
- 控制单表单字段数量的目的是为了控制数据行的长度避免出现行迁移和行链接。如果计算行长度避免出现行链接或行迁移呢?MYSQL
的数据行是存储在数据页中,数据页的大小是16KB(默认16KB),file header、Page
Header、File Trailer 占用了102字节,Page Directory
记录数据行在数据页的位置也需要消耗数据页空间,建议把总消耗空间按1KB算,也就是说数据页可以空间还剩15KB。15KB除去行长度可以整除就可以避免行链接,尽量少使用可变长度的大字段可以有效减少行迁移。表列数量建议控制在30个以内。
冷热数据分离
- 访问频率较低的大字段拆分出数据表,以免造成IO资源、缓存资源的浪费。经常一起使用的列应该放到一个表中,允许适当冗余,避免更多的关联操作。
采用合适的分库分表策略
大表查询效率很低,需要考虑水平拆分。根据业务特性有很多拆分方式。符合时间递增的表,可以根据时间来分,也可以ID的HASH方式来拆分。
-
如果按HASH散表,表名后缀使用十进制,下标从0开始。考虑后续的扩容,建议使用二叉树分库分表策略。
-
如果按日期时间散表,表名需要符合YYYY[MM][DD][HH][mm][sss]的格式。
根据需要设计汇总表
- 多表关联查询会很慢,可以根据实际情况,考虑在业务上汇总,记录到汇总表。
字段设计规范
基本规范
-
存储相同数据的列名和列类型必须一致,否则会导致隐式转换,造成索引失效,降低查询效率。
-
在最大限度的满足可能的需要的前提下,字段应该尽可能的设计得短一些,以提高查询的效率,且降低索引对资源的消耗。
-
数据行的长度不要超过8020字节,如果超过这个长度的话在物理页中插入两行数据就会出现行链接从而造成存储碎片,降低查询效率。
-
单表列数量建议控制在30个以内。
-
尽量使用整型字段,代替IP、枚举类型、字符类型、浮点数类型。
-
所有字段都需要默认值,如有特殊情况,另作讨论决定。
字符字段
-
用户名、密码等长度变化不大的字段选择CHAR类型。
-
其他不确定长度的字段,统一使用varchar相关的类型。
整型字段
-
明确无符号的数值,使用 unsigned的整型。
-
能够用整型的字段尽量整型,提高查询和连接的性能,降低存储开销、CPU计算开销。如enum、ip、小额货币等。
Enum字段
- 禁止使用enum,可使用tinyint代替。
因为修改ENUM需要使用ALTER语句,需要进行DDL操作, ENUM类型的ORDER
BY操作效率低,需要额外操作
默认值
- 所有字段都需要默认值,不允许为null,避免无法使用索引或null值引发BUG,如有特殊情况,可以存储空白字符代替null。
Null字段难以进行查询优化,索引需要额外的空间,复合索引无效,整体降低数据库处理的性能,也容易导致应用层程序报空指针异常。
二进制数据
- 禁止在数据库上存储图片、二进制文件等静态资源,应该使用合适的文件系统,数据库仅存储URL对于二进制多媒体数据、超大文本数据也不要放在数据库字段中。
Text/Blob字段
-
一般避免使用text、blob等类型字段,会浪费更多的磁盘和内存空间,非必要的大量的大字段查询会淘汰掉热数据,导致内存命中率急剧降低,影响数据库性能。
-
考虑使用varchar来代替,如果一定要使用text/blob,要离到单独的扩展表中,如果要用到索引,只能使用前缀索引。
日期时间字段
- timestamp类型比较精简,可以提高查询效率,减少磁盘空间及IO,但范围是1970年-2038年,考虑企业的历史及将来,建议使用datetime类型存储日期时间。
金额字段
-
禁止使用float、double来定义金额字段,建议使用decimal类型或者bigint类型。
-
金额字段使用decimal类型,并给予足够的长度及精度。在性能要求比较苛刻的情况下,使用bigint类型,单位是分(如果是其他货币,需要定义其他单位)。
其他业务字段
电话字段
- 考虑到区号或者国家代号可能会涉及到±()等符号,并且需要支持模糊查询,所以应该使用字符类型,如varchar等
。
坐标字段
- 表示坐标(0,0),应该使用两列表示,而不是将“0,0”放在1个列中。
不建议使用预留字段
-
预留字段的命名很难做到见名识义。
-
预留字段无法确认存储的数据类型,所以无法选择合适的类型。
-
预留字段是一种“过度设计”,我们应该做的就是“按需设计”,在经过详细有效的分析之后,在数据表中只放置必要的字段,而不要留出大量的备用字段。
索引设计规范
索引可以提高查询效率,但会降低更新效率,所以索引不是越多越好,原则是能不加就不加,要加的一定得加。
控制单表索引数量
- 单表索引数量不超过5个。
控制单个索引的字段数量
- 单个索引中的字段数不超过5个。
对于更新频繁的字段要评估读写比例和创建索引后的性能收益和醒脑静损坏比例再决定是否创建索引
- 对于频繁更新的字段是否适合创建索引要评估该字段读写比例再决定是否创建索引。比如一个字段每秒更新20次,但每秒查询达到100次,而且是直接通过该字段来定位数据行的,如果该字段没有索引就会导致全表扫描,如果更新也是需要使用该字段定位数据行也会导致更新出现全表扫描,这种情况就是一定要创建索引的。(相对应的一种情况是通过数据行的ID可以定位到数据行,不需要使用被更新字段定位数据行,这种情况就不适合创建索引)。
禁止在区分度不高的属性上建立索引
- 如“性别”这种区分度不大的字段,建立索引对查询性能的提升有限,与全表扫描差别不大。
建立组合索引字段顺序优先级
-
使用频率高(大量SQL 过滤条件都使用了这个字段)
-
使用频率高
-
区分度高范围查询
建立长字符串字段的前缀索引
- 保证快速有效过滤数据的同时,节省维护索引的开销。
避免冗余重复索引
-
已经建立唯一索引的字段,没有必要再建立与该字段有关的联合索引。
-
不要建立查询条件里根本不会出现的字段的索引或者联合索引。
选择合适的索引类型
- 唯一确定一条记录的一个字段或多个字段要建立主键或者唯一索引,不能唯一确定一条记录,为了提高查询效率建立普通索引。
建立索引时必须考虑索引返回的记录稠密度
- 业务通过不唯一索引访问数据时,需要考虑通过该索引值返回的记录稠密度,原则上稠密度最大不能高于0.2,如果稠密度太大,则不合适建立索引了。
当通过这个索引查找得到的数据量占到表内所有数据的20%以上时,则需要考虑建立该索引的代价,同时由于索引扫描产生的都是随机I/O,其效率比全表顺序扫描的顺序I/O低很多。数据库系统优化query的时候有可能不会用到这个索引。
注意联合索引的顺序
-
联合索引中各字段的顺序,要与查询语句的字段顺序保持一致,否则可能无法应用索引。
-
区分度最高的放在联合索引的最左侧。
-
使用最频繁的列放到联合索引的左侧。
-
尽量把字段长度小的列放在联合索引的最左侧。
主键设计规范
-
一般不使用联合主键。
-
必须指定主键,建议使用内存型、数值型字段做主建,以应对大数据高并发的业务场景。如果使用自增列,在一定程度上依赖了数据库自身的特性,同时也要考虑分布式环境的全局唯一性。UUID是字符类型,增加索引磁盘空间及CPU开销,且不具备自增特性。
其他规范
在大数据、高并发的互联网业务,架构设计的思路是解放数据库,让应用层承担更到的责任。一般禁止使用与数据库自身特性相关的对象,如存储过程、触发器、视图等,降低业务耦合度,让数据库做最擅长的事情。
触发器设计规范
-
禁止使用数据库的触发器特性,请在应用层寻求对应的解决方案。
-
如有特殊需求,另行研究决定。
存储过程设计规范
-
禁止使用数据库的存储过程特性,请在应用层寻求对应的解决方案。
-
如有特殊需求,另行研究决定。
函数设计规范
-
禁止使用数据库的函数特性,请在应用层寻求对应的解决方案。
-
如有特殊需求,另行研究决定。
外键设计规范
- 禁止使用数据库的外键特性,请在应用层寻求对应的解决方案。如有特殊需求,另行研究决定。
注意:外键会导致表与表之间耦合,update与delete操作都会涉及相关联的表,影响sql 的性能,甚至会造成死锁,大数据高并发业务场景下容易造成数据库性能大幅下降。
约束设计规范
- 本规范禁止使用数据库的约束特性,请在应用层寻求对应的解决方案。如有特殊需求,另行研究决定。
注意:主键自身会有唯一性约束,其他约束如check、外键等,建议在应用层实现。
表分区设计规范
- 本规范禁止使用数据库的表分区特性,请在应用层寻求对应的解决方案。如有特殊需求,另行研究决定。
注:分区表在物理上表现为多个文件,在逻辑上表现为一个表,实际性能不是非常好,且管理维护成本较高,建议采用物理分表的方式管理大数据,请参考分库分表策略相关的文档。
命名规范
基本规范
对数据库所有对象的命名,进行以下约定:
-
统一小写格式。
-
统一使用英文字母,数字和下划线来命名,禁止使用其他字符,如中横线等。
-
不超过32个字符,须见名知意,易于辨识。
-
禁止使用拼音来命名,禁止拼音英文混用。
-
禁止使用关键字,可以加上前缀区别关键字。
-
临时库、临时表名必须以tmp为前缀并以时间戳为后缀。
-
备份库、备份表名必须以bak为前缀并以时间戳为后缀。
-
不同表中,存储相同数据的列名要保持一致。
库命名规范
参考格式:<前缀>[_业务类型/产品类型/其他类型]_<库名>。
-
前缀:必选项,如gtmc。
-
类型:非必选,但需要所有库要统一选还是不选。参考类型:产品类型/业务类型/其他类型。
-
库名:应尽可能和所服务的业务模块名一致。
参考命名:
<前缀>_<库名> | <前缀>_<类型>_<库名> |
---|---|
项目缩写_order | 项目缩写_ssp_order |
项目缩写_goods | 项目缩写_ssp_goods |
项目缩写_payment | 项目缩写_ssp_payment |
项目缩写_member | 项目缩写_ssp_member |
项目缩写_merchant | 项目缩写_ssp_merchant |
项目缩写_marketing | 项目缩写_ ssp_marketing |
项目缩写_asset | 项目缩写_ssp_asset |
项目缩写_cms | 项目缩写_ssp_cms |
…… | …… |
表命名规范
常规表命名
参考格式:<库名/库名缩写>_<表名/表名缩写>。
-
表名应尽可能和所服务的业务模块名一致。
-
表名应尽量包含与所存放数据对应的单词或者缩写。
-
同一个模块的表应尽量以模块名(或缩写)为前缀。
参考命名:
<库名缩写>_<表名/表名缩写> | |
---|---|
ast_account | |
ast_account_recharge | |
ast_account_withdraw | |
ast_account_consume | |
…… |
主从表命名
主表参考格式:请参考上一节描述。
从表参考格式:<主表名>_<从表关键字>。
- 从表关键字:优先选从表实体名,如果从表的对象类型不唯一,可以选择item类似的词汇来表达,需要全局统一,形成规范。
参考命名:
<主表名>_<从表实体> | <主表名>_<其他词汇> |
---|---|
ord_order | ord_order |
ord_order_goods | ord_order_item |
ord_member | |
ord_member_address | |
…… | …… |
关联表命名
参考格式: <表名1>_<表名2>_rel。
参考命名:
表名1 | 表名2 | <表名1>_<表名2>_rel |
---|---|---|
bas_category | bas_attribute | bas_category_attr_rel |
字段命名规范
参考格式:[前缀_]<字段名>。
-
一般不用前缀(当和关键词冲突的可以考虑加前缀区别)。
-
字段名称也应尽量保持和实际数据相对应。
参考命名:
[前缀_]<字段名> | |
---|---|
account_id | |
account_name | |
account_type | |
owner_id | |
owner_type | |
mobile | |
…… |
索引命名规范
普通索引:idx_<表名/表名缩写>_<列名/列名缩写[_列名/列名缩写]>。
唯一索引:uidx_<表名/表名缩写>_<列名/列名缩写[_列名/列名缩写]>。
备注:
-
【idx】:表示索引,英文index。
-
【uidx】:表示唯一索引,英文unique index。
-
联合索引名称应尽量包含所有索引键字段名或缩写,且各字段名在索引名中的顺序应与索引键在索引中的索引顺序一致。
参考命名:
普通索引 | 唯一索引 |
---|---|
idx_ord_order_num | uidx_account_oid_otype:(ownerId,ownerType) |
…… | …… |
MySQL关键字
MySQL关键字 | ||
---|---|---|
ADD | ALL | ALTER |
ANALYZE | AND | AS |
ASC | ASENSITIVE | BEFORE |
BETWEEN | BIGINT | BINARY |
BLOB | BOTH | BY |
CALL | CASCADE | CASE |
CHANGE | CHAR | CHARACTER |
CHECK | COLLATE | COLUMN |
CONDITION | CONNECTION | CONSTRAINT |
CONTINUE | CONVERT | CREATE |
CROSS | CURRENT_DATE | CURRENT_TIME |
CURRENT_TIMESTAMP | CURRENT_USER | CURSOR |
DATABASE | DATABASES | DAY_HOUR |
DAY_MICROSECOND | DAY_MINUTE | DAY_SECOND |
DEC | DECIMAL | DECLARE |
DEFAULT | DELAYED | DELETE |
DESC | DESCRIBE | DETERMINISTIC |
DISTINCT | DISTINCTROW | DIV |
DOUBLE | DROP | DUAL |
EACH | ELSE | ELSEIF |
ENCLOSED | ESCAPED | EXISTS |
EXIT | EXPLAIN | FALSE |
FETCH | FLOAT | FLOAT4 |
FLOAT8 | FOR | FORCE |
FOREIGN | FROM | FULLTEXT |
GOTO | GRANT | GROUP |
HAVING | HIGH_PRIORITY | HOUR_MICROSECOND |
HOUR_MINUTE | HOUR_SECOND | IF |
IGNORE | IN | INDEX |
INFILE | INNER | INOUT |
INSENSITIVE | INSERT | INT |
INT1 | INT2 | INT3 |
INT4 | INT8 | INTEGER |
INTERVAL | INTO | IS |
ITERATE | JOIN | KEY |
KEYS | KILL | LABEL |
LEADING | LEAVE | LEFT |
LIKE | LIMIT | LINEAR |
LINES | LOAD | LOCALTIME |
LOCALTIMESTAMP | LOCK | LONG |
LONGBLOB | LONGTEXT | LOOP |
LOW_PRIORITY | MATCH | MEDIUMBLOB |
MEDIUMINT | MEDIUMTEXT | MIDDLEINT |
MINUTE_MICROSECOND | MINUTE_SECOND | MOD |
MODIFIES | NATURAL | NOT |
NO_WRITE_TO_BINLOG | NULL | NUMERIC |
ON | OPTIMIZE | OPTION |
OPTIONALLY | OR | ORDER |
OUT | OUTER | OUTFILE |
PRECISION | PRIMARY | PROCEDURE |
PURGE | RAID0 | RANGE |
READ | READS | REAL |
REFERENCES | REGEXP | RELEASE |
RENAME | REPEAT | REPLACE |
REQUIRE | RESTRICT | RETURN |
REVOKE | RIGHT | RLIKE |
SCHEMA | SCHEMAS | SECOND_MICROSECOND |
SELECT | SENSITIVE | SEPARATOR |
SET | SHOW | SMALLINT |
SPATIAL | SPECIFIC | SQL |
SQLEXCEPTION | SQLSTATE | SQLWARNING |
SQL_BIG_RESULT | SQL_CALC_FOUND_ROWS | SQL_SMALL_RESULT |
SSL | STARTING | STRAIGHT_JOIN |
TABLE | TERMINATED | THEN |
TINYBLOB | TINYINT | TINYTEXT |
TO | TRAILING | TRIGGER |
TRUE | UNDO | UNION |
UNIQUE | UNLOCK | UNSIGNED |
UPDATE | USAGE | USE |
USING | UTC_DATE | UTC_TIME |
UTC_TIMESTAMP | VALUES | VARBINARY |
VARCHAR | VARCHARACTER | VARYING |
WHEN | WHERE | WHILE |
WITH | WRITE | X509 |
XOR | YEAR_MONTH | ZEROFILL |
具体版本的关键字,请参考以下地址:
https://dev.mysql.com/doc/refman/8.0/en/keywords.html
https://dev.mysql.com/doc/refman/5.7/en/keywords.html
https://dev.mysql.com/doc/refman/5.6/en/keywords.html
SQL规范
in/or
-
or的效率是n级别,in的效率是log(n)级别。
-
应尽量避免在 where 子句中使用 or
来连接条件,否则将导致引擎放弃使用索引而进行全表扫描。 -
in的个数建议控制在1000以内,避免使用在大集合中使用in。
select *
- 禁止使用SELECT
*,应用层应指定所要的字段,避免消耗不必要的CPU、硬盘IO及网络带宽。
union all
- 使用union all替代union,union有去重开销,尽量由应用层实现去重。
模糊查询
-
禁止使用全模糊查询,无法使用索引,导致全表扫描。
-
可以使用右模糊查询,如like‘xxx%’,可以正常应用索引。
反向查询
- 禁止使用反向查询,如NOT、!=、<>、!<、!>、NOT IN、NOT
LIKE等,会导致全表扫描。
隐式类型转换
- 禁止使用隐式转换,会导致索引失效。
Join
- 大表连接字段和其他过滤条件字段没有合适的索引,禁止大表使用JOIN查询。
注意:大表join查询如果全表扫描,会产生临时表,消耗较多内存与CPU,极大影响数据库性能。
SQL解析
- 尽量避免相同功能的语句由于格式的不同,而导致多次解析。
SQL表达式
- 避免在数据库中使用数学运算、函数等,容易将业务逻辑和DB耦合在一起,且容易导致索引失效。
多表更新
- 禁止单SQL语句同时更新多个表。
交互
- 减少与数据库的交互次数。
Load data
- 使用load data导数据,load data比insert快约20倍。
避免大SQL
-
一条sql只能在一个cpu运算,大语句拆小语句,减少锁时间。
-
大sql需要拆分成小sql,充分利用多核CPU。
避免大批量
-
大批量写操作会产生大量日志,日志传输和恢复所需要的时间过长,造成主从环境数据同步严重延迟。
-
Insert语句中,根据测试,批量一次插入1000条时效率最高,多于1000条时,要拆分,多次进行同样的插入,应该合并批量进行。
避免大事务
-
遵循事务相关性最小原则。
-
事务尽量简单,事务时间尽可能短。大批量修改数据,一定是在一个事务中进行的,这就会造成表中大批量数据进行锁定,从而导致大量的阻塞,阻塞会对数据库的性能产生非常大的影响。
索引字段的顺序
- 查询条件中的字段,要把最有效的索引字段写在前面,同时要注意联合索引中的字段顺序。
insert into必须指定插入列
- 禁止使用INSERT INTO t_xxx VALUES(xxx),必须显示指定插入的列属性。
DDL操作
-
应用程序里的 SQL 语句,禁止一切 DDL 操作。
-
如有特殊需要,必需与 DBA 协商同意方可使用。
sysdate()
- sysdate取的是系统主机时间,在
binlog为语句模式时会原文传输,导致主从库数据产生差异。所以 binlog
强烈建议使用行(row)模式。
避免多余的排序
- 使用 GROUP BY 时,默认会进行排序,当你不需要排序时,可以使用order by null。
聚合函数
注意以下事项:
-
使用count(column_name)代替count(1)和count(*)。
-
count(column_name)计算该列不为 NULL 的记录条数。
-
count(distinct column_name)计算该列不为 NULL 的不重复值数量。
-
count()函数不会返回 NULL,但 sum()函数可能返回 NULL。
最有效的过滤字段
- 使用最有效的过滤字段,where 字句中的过滤条件返回的记录数以少为好。
数据库域名规范
- 禁止使用IP连接数据库。
各个环境域名规范(xxx业务模块) | |
---|---|
开发环境 | d.xxx.db |
测试环境 | t.xxx.db |
生产环境 | p.xxx.db |
…… | …… |
主从库域名命令规范 | |
生产环境主库 | p.xxx.db |
生产环境从库01 | ps-01.xxx.db |
生产环境从库02 | Ps-02.xxx.db |
…… | …… |
备注:
-
生产环境,英文取Production,缩写p。
-
开发环境,英文取Development,缩写d。
-
测试环境,英文取Test,缩写t。
-
从库,英文取Slave,缩写s。
-
主库,英文取Master,缩写m。
行为规范
行为规范 | |
---|---|
禁止 | 禁止分配super权限的账号给应用程序使用,super权限只能留给DBA处理问题的账号使用。 |
禁止 | 禁止在数据库中存储明文密码。 |
禁止 | 禁止从开发环境、测试环境直连线上数据库。 |
禁止 | 禁止在线上做数据库压力测试。 |
禁止 | 禁止使用IP连接数据库,应该使用内网域名。 |
禁止 | 禁止在生产环境创建test库。 |
禁止 | 合理分配数据库账号所拥有的权限,如应用程序账号原则上不准有drop权限。 |
注意 | 导入导出数据必须提前通知DBA,并让DBA协助观察。 |
注意 | 促销活动或者上线新功能必须提前通知DBA进行流量评估。 |
注意 | 不在业务高峰期批量更新,查询数据库。 |
注意 | 进行DDL/DML操作时,需要DBA进行审查,并在执行过程中观察服务负载等各种指标。 |
注意 | 对特别重要的库表,提前与DBA沟通确定维护和备份优先级。 |
高并发高可用
在大数据高并发的场景之下,数据库最终会成为性能的瓶颈,如何在巨量的数据请求之下,提供稳定可靠的数据服务,将是对数据库设计终极考验,设计者应该未雨绸缪,及早策划应对。
以下是对数据库高并发、高可用设计的一些基本概括,仅供数据库设计者参考。
主从部署
数据库采用主从部署方式,这是目前最简单的高可用方式。主从部署,主写从读,读写分离。当读操作大于写操作的时候,这种方案带来的性能提升是很明显的。
主从复制
几乎所有的主流数据库都支持复制,这是进行数据库简单扩展的基本手段。下面以Mysql为例来说明,它支持主从复制,配置也并不复杂,只需要开启主服务器上的二进制日志以及在主服务器和从服务器上分别进行简单的配置和授权。Mysql的主从复制是依据主服务器的二进制日志文件进行的,主服务器日志中记录的操作会在从服务器上重放,从而实现复制,所以主服务器必须开启二进制日志,自动记录所有对于主数据库的更新操作,从服务器再定时到主服务器取得二进制日志文件进行重放则完成了数据的复制。主从复制也用于自动备份。
读写分离
为保证数据库数据的一致性,我们要求所有对于数据库的更新操作都是针对主数据库的,但是读操作是可以针对从数据库来进行。大多数站点的数据库读操作比写操作更加密集,而且查询条件相对复杂,数据库的大部分性能消耗在查询操作上了。
主从复制数据是异步完成的,这就导致主从数据库中的数据有一定的延迟,在读写分离的设计中必须要考虑这一点。对于当前用户就需要读主数据库,对于其他访问量更大的外部用户就可以读从数据库。
负载均衡
在读写分离的方式使用主从部署方式的数据库的时候,会遇到一个问题,一个主数据库对应多台从服务器,对于写操作是针对主数据库的,数据库个数是唯一的,但是对于从服务器的读操作就需要使用适当的算法来分配请求啦,尤其对于多个从服务器的配置不一样的时候甚至需要读操作按照权重来分配。
对于上述问题可以使用数据库方向代理来实现。就像WEB反向代理服务器一样,Mysql
Proxy同样可以在SQL语句转发到后端的Mysql服务器之前对它进行修改。
分库分表
随着时间增长,主要的业务表数据会急剧增长,如果是单库单表的形式,就目前的硬件水平,很容易就会达到性能瓶颈,对主要的业务进行分库分表是最终的解决方案。
分库策略建议选择了“二叉树分库”策略,主要是方便日后扩容,降低数据迁移的成本及出错风险。所谓“二叉树分库”指的是:在进行数据库扩容时,都是以2的倍数进行扩容。比如:1台扩容到2台,2台扩容到4台,4台扩容到8台,以此类推。这种方式扩容时,只需DBA进行表级的数据同步,而不需要进行行级数据同步。
光有分库依然不够的,在同一数据库中,对多个表进行并发更新的效率要远远大于对一个表进行并发更新,所以在每个分库中都可以再分表。
数据分级
根据数据的读写频率、实时性要求可以对数据进行分级处理。
第1级:如订单数据和支付数据,对实时性和精确性要求很高,所以不添加任何缓存,读写操作将直接操作数据库。
第2级:用户相关数据,具有读多写少的特征,所以我们使用一些缓存机制,如redis等。
第3级:配置信息,这些数据和用户无关,具有数据量小,频繁读,几乎不修改的特征,所以我们使用本地内存进行缓存。
其他
主数据库的,数据库个数是唯一的,但是对于从服务器的读操作就需要使用适当的算法来分配请求啦,尤其对于多个从服务器的配置不一样的时候甚至需要读操作按照权重来分配。
对于上述问题可以使用数据库方向代理来实现。就像WEB反向代理服务器一样,Mysql
Proxy同样可以在SQL语句转发到后端的Mysql服务器之前对它进行修改。
分库分表
随着时间增长,主要的业务表数据会急剧增长,如果是单库单表的形式,就目前的硬件水平,很容易就会达到性能瓶颈,对主要的业务进行分库分表是最终的解决方案。
分库策略建议选择了“二叉树分库”策略,主要是方便日后扩容,降低数据迁移的成本及出错风险。所谓“二叉树分库”指的是:在进行数据库扩容时,都是以2的倍数进行扩容。比如:1台扩容到2台,2台扩容到4台,4台扩容到8台,以此类推。这种方式扩容时,只需DBA进行表级的数据同步,而不需要进行行级数据同步。
光有分库依然不够的,在同一数据库中,对多个表进行并发更新的效率要远远大于对一个表进行并发更新,所以在每个分库中都可以再分表。
数据分级
根据数据的读写频率、实时性要求可以对数据进行分级处理。
第1级:如订单数据和支付数据,对实时性和精确性要求很高,所以不添加任何缓存,读写操作将直接操作数据库。
第2级:用户相关数据,具有读多写少的特征,所以我们使用一些缓存机制,如redis等。
第3级:配置信息,这些数据和用户无关,具有数据量小,频繁读,几乎不修改的特征,所以我们使用本地内存进行缓存。
其他
数据库在系统中的定位极为重要,需要精细化设计部署,同时需要应用层架构的配合,方能实现良好的水平扩展,最终实现高并发高可用。