1.命名规范
(1)库名、表名、字段名必须使⽤⼩写字⺟,并采⽤下划线分割。
(2)库名、表名、字段名禁⽌超过32个字符。
(3)库名、表名、字段名必须⻅名知意。命名与业务、产品线等相关联。
(4)库名、表名、字段名禁⽌使⽤MySQL保留字。
(5)临时库、表名必须以tmp为前缀,并以⽇期为后缀。例如 tmp_test01_20130704。
(6)备份库、表必须以bak为前缀,并以⽇期为后缀。例如 bak_test01_20130704。

2.基础规范
(1)使⽤INNODB存储引擎。
(2)表字符集使⽤UTF8,必要时可申请使⽤UTF8MB4字符集。
(3)所有表都需要添加注释;除主键外的其他字段都需要增加注释。推荐采⽤英⽂标点,避免出现乱码。
【建表语句⽰例】
(4)禁⽌在数据库中存储图⽚、⽂件等⼤数据。
(5)每张表数据量建议控制在5000W以内。
(6)禁⽌在线上做数据库压⼒测试。
(7)禁⽌从测试、开发环境直连数据库。

3.库表设计
(1)禁⽌使⽤分区表。
(2)将⼤字段、访问频率低的字段拆分到单独的表中存储,分离冷热数据。
(3)推荐使⽤HASH进⾏散表,表名后缀使⽤⼗进制数,数字必须从0开始。
(4)按⽇期时间分表需符合YYYY[MM][DD][HH]格式,例如2013071601。年份必须⽤4位数字表⽰。例如按
⽇散表user_20110209、 按月散表user_201102。
(5)采⽤合适的分库分表策略。例如千库⼗表、⼗库百表等。

4.字段设计
(1)建议使⽤UNSIGNED存储⾮负数值。
(2)建议使⽤INT UNSIGNED存储IPV4。
(3)⽤DECIMAL代替FLOAT和DOUBLE存储精确浮点数。例如与货币、⾦融相关的数据。
(4)INT类型固定占⽤4字节存储,例如INT(4)仅代表显⽰字符宽度为4位,不代表存储⻓度。
(5)区分使⽤TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT数据类型。例如取值范围为0-80时,使⽤
TINYINT UNSIGNED。
(6)强烈建议使⽤TINYINT来代替ENUM类型。
(7)尽可能不使⽤TEXT、BLOB类型。
(8)禁⽌在数据库中存储明⽂密码。
(9)使⽤VARBINARY存储⼤⼩写敏感的变⻓字符串或⼆进制内容。
(10)使⽤尽可能⼩的VARCHAR字段。VARCHAR(N)中的N表⽰字符数⽽⾮字节数。
(11)区分使⽤DATETIME和TIMESTAMP。存储年使⽤YEAR类型。存储⽇期使⽤DATE类型。 存储时间(精确
到秒)建议使⽤TIMESTAMP类型。
(12)所有字段均定义为NOT NULL。

5.索引规范
(1)单张表中索引数量不超过5个。
(2)单个索引中的字段数不超过5个。
(3)索引名必须全部使⽤⼩写。
(4)⾮唯⼀索引按照“idx_字段名称[_字段名称]”进⾏命名。例如idx_age_name。
(5)唯⼀索引按照“uniq_字段名称[_字段名称]”进⾏命名。例如uniq_age_name。
(6)组合索引建议包含所有字段名,过⻓的字段名可以采⽤缩写形式。例如idx_age_name_add。
(7)表必须有主键,推荐使⽤UNSIGNED⾃增列作为主键。
(8)唯⼀键由3个以下字段组成,并且字段都是整形时,可使⽤唯⼀键作为主键。其他情况下,建议使⽤⾃增列
或发号器作主键。
(9)禁⽌冗余索引。
(10)禁⽌重复索引。
(11)禁⽌使⽤外键。
(12)联表查询时,JOIN列的数据类型必须相同,并且要建⽴索引。
(13)不在低基数列上建⽴索引,例如“性别”。
(14)选择区分度⼤的列建⽴索引。组合索引中,区分度⼤的字段放在最前。
(15)对字符串使⽤前缀索引,前缀索引⻓度不超过8个字符。
(16)不对过⻓的VARCHAR字段建⽴索引。建议优先考虑前缀索引,或添加CRC32或MD5伪列并建⽴索引。
(17)合理创建联合索引,(a,b,c) 相当于 (a) 、(a,b) 、(a,b,c)。
(18)合理使⽤覆盖索引减少IO,避免排序。

6.SQL设计
(1)使⽤prepared statement,可以提升性能并避免SQL注⼊。
(2)⽤IN代替OR。SQL语句中IN包含的值不应过多,应少于1000个。
(3)禁⽌隐式转换。数值类型禁⽌加引号;字符串类型必须加引号。
(4)避免使⽤JOIN和⼦查询。必要时推荐⽤JOIN代替⼦查询。
(5)避免在MySQL中进⾏数学运算和函数运算。
(6)减少与数据库交互次数,尽量采⽤批量SQL语句。
(7)拆分复杂SQL为多个⼩SQL,避免⼤事务。
(8)获取⼤量数据时,建议分批次获取数据,每次获取数据少于2000条,结果集应⼩于1M。
(9)⽤UNION ALL代替UNION。
(10)统计⾏数⽤COUNT(*)。
(11)SELECT只获取必要的字段,禁⽌使⽤SELECT *。
(12)SQL中避免出现now()、rand()、sysdate()、current_user()等不确定结果的函数。
(13)INSERT语句必须指定字段列表,禁⽌使⽤ INSERT INTO TABLE()。
(14)禁⽌单条SQL语句同时更新多个表。
(15)避免使⽤存储过程、触发器、视图、⾃定义函数等。
(16)建议使⽤合理的分⻚⽅式以提⾼分⻚效率。
(17)禁⽌在从库上执⾏后台管理和统计类功能的QUERY,必要时申请统计类从库。
(18)程序应有捕获SQL异常的处理机制,必要时通过rollback显式回滚。
(19)重要SQL必须被索引:update、delete的where条件列、order by、group by、distinct字段、多表join
字段。
(20)禁⽌使⽤%前导查询,例如:like “%abc”,⽆法利⽤到索引。
(21)禁⽌使⽤负向查询,例如 not in、!=、not like。
(22)使⽤EXPLAIN判断SQL语句是否合理使⽤索引,尽量避免extra列出现:Using File Sort、Using
Temporary。
(23)禁⽌使⽤order by rand()。

7.⾏为规范
(1)表结构变更必须通知DBA进⾏审核。
(2)禁⽌有super权限的应⽤程序账号存在。
(3)禁⽌有DDL、DCL权限的应⽤程序账号存在。
(4)重⼤项⺫的数据库⽅案选型和设计必须提前通知DBA参与。
(5)批量导⼊、导出数据必须通过DBA审核,并在执⾏过程中观察服务。
(6)批量更新数据,如UPDATE、DELETE操作,必须DBA进⾏审核,并在执⾏过程中观察服务。
(7)产品出现⾮数据库导致的故障时,如被攻击,必须及时通DBA,便于维护服务稳定。
(8)业务部⻔程序出现BUG等影响数据库服务的问题,必须及时通知DBA,便于维护服务稳定。
(9)业务部⻔推⼲活动或上线新功能,必须提前通知DBA进⾏服务和访问量评估,并留出必要时间以便DBA完
成扩容。
(10)出现业务部⻔⼈为误操作导致数据丢失,需要恢复数据的,必须第⼀时间通知DBA,并提供准确时间点、
误操作语句等重要线索。
(11)提交线上建表改表需求,必须详细注明涉及到的所有SQL语句(包括INSERT、DELETE、UPDATE),便
于DBA进⾏审核和优化。
(12)对同⼀个表的多次alter操作必须合并为⼀次操作。
(13)不要在MySQL数据库中存放业务逻辑。

8.FAQ
1.库名、表名、字段名必须使⽤⼩写字⺟,并采⽤下划线分割。
a)MySQL有配置参数lower_case_table_names,不可动态更改,linux系统默认为 0,即库表名以实际情况
存储,⼤⼩写敏感。如果是1,以⼩写存储,⼤⼩写不敏感。如果是2,以实际情况存储,但以⼩写⽐较。
b)如果⼤⼩写混合使⽤,可能存在abc,Abc,ABC等多个表共存,容易导致混乱。
c)字段名显⽰区分⼤⼩写,但实际使⽤不区分,即不可以建⽴两个名字⼀样但⼤⼩写不⼀样的字段。
d)为了统⼀规范, 库名、表名、字段名使⽤⼩写字⺟。
2.库名、表名、字段名禁⽌超过32个字符。
库名、表名、字段名⽀持最多64个字符,但为了统⼀规范、易于辨识以及减少传输量,禁⽌超过32个字符。

3.使⽤INNODB存储引擎。
INNODB引擎是MySQL5.5版本以后的默认引擘,⽀持事务、⾏级锁,有更好的数据恢复能⼒、更好的并发性
能,同时对多核、⼤内存、SSD等硬件⽀持更好,⽀持数据热备份等,因此INNODB相⽐MyISAM有明显优
势。
4.库名、表名、字段名禁⽌使⽤MySQL保留字。
当库名、表名、字段名等属性含有保留字时,SQL语句必须⽤反引号引⽤属性名称,这将使得SQL语句书写、
SHELL脚本中变量的转义等变得⾮常复杂。
5.禁⽌使⽤分区表。
分区表对分区键有严格要求;分区表在表变⼤后,执⾏DDL、SHARDING、单表恢复等都变得更加困难。因此
禁⽌使⽤分区表,并建议业务端⼿动SHARDING。
6.建议使⽤UNSIGNED存储⾮负数值。
同样的字节数,⾮负存储的数值范围更⼤。如TINYINT有符号为 -128-127,⽆符号为0-255。
7.建议使⽤INT UNSIGNED存储IPV4。⽤UNSINGED INT存储IP地址占⽤4字节,CHAR(15)则占⽤15字节。另外,计算机处理整数类型⽐字符串类
型快。使⽤INT UNSIGNED⽽不是CHAR(15)来存储IPV4地址,通过MySQL函数inet_ntoa和inet_aton来进⾏
转化。IPv6地址⺫前没有转化函数,需要使⽤DECIMAL或两个BIGINT来存储。例如:
SELECT INET_ATON('209.207.224.40'); 3520061480
SELECT INET_NTOA(3520061480); 209.207.224.40
8.强烈建议使⽤TINYINT来代替ENUM类型。
ENUM类型在需要修改或增加枚举值时,需要在线DDL,成本较⾼;ENUM列值如果含有数字类型,可能会引
起默认值混淆。【ENUM类型说明】
9.使⽤VARBINARY存储⼤⼩写敏感的变⻓字符串或⼆进制内容。
VARBINARY默认区分⼤⼩写,没有字符集概念,速度快。
10.INT类型固定占⽤4字节存储,例如INT(4)仅代表显⽰字符宽度为4位,不代表存储⻓度。
数值类型括号后⾯的数字只是表⽰宽度⽽跟存储范围没有关系,⽐如INT(3)默认显⽰3位,空格补⻬,超出时
正常显⽰,python、java客户端等不具备这个功能。
11.区分使⽤DATETIME和TIMESTAMP。存储年使⽤YEAR类型。存储⽇期使⽤DATE类型。 存
储时间(精确到秒)建议使⽤TIMESTAMP类型。
DATETIME和TIMESTAMP都是精确到秒,优先选择TIMESTAMP,因为TIMESTAMP只有4个字节,⽽
DATETIME8个字节。同时TIMESTAMP具有⾃动赋值以及⾃动更新的特性。注意:在5.5和之前的版本中,如
果⼀个表中有多个timestamp列,那么最多只能有⼀列能具有⾃动更新功能。
如何使⽤TIMESTAMP的⾃动赋值属性?
a)⾃动初始化,⽽且⾃动更新: column1 TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE
CURRENT_TIMESTAMP
b)只是⾃动初始化: column1 TIMESTAMP DEFAULT CURRENT_TIMESTAMP
c)⾃动更新,初始化的值为0:column1 TIMESTAMP DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP
d)初始化的值为0:column1 TIMESTAMP DEFAULT 0 【TIMESTAMP字段类型初始化】
12.所有字段均定义为NOT NULL。
a)对表的每⼀⾏,每个为NULL的列都需要额外的空间来标识。
b)B树索引时不会存储NULL值,所以如果索引字段可以为NULL,索引效率会下降。
c)建议⽤0、特殊值或空串代替NULL值。

9、默认约定说明
1.将⼤字段、访问频率低的字段拆分到单独的表中存储,分离冷热数据。
有利于有效利⽤缓存,防⽌读⼊⽆⽤的冷数据,较少磁盘IO,同时保证热数据常驻内存提⾼缓存命中率。

2.禁⽌在数据库中存储明⽂密码。
采⽤加密字符串存储密码,并保证密码不可解密,同时采⽤随机字符串加盐保证密码安全。防⽌数据库数据被
公司内部⼈员或⿊客获取后,采⽤字典攻击等⽅式暴⼒破解⽤户密码。

3.表必须有主键,推荐使⽤UNSIGNED⾃增列作为主键。
表没有主键,INNODB会默认设置隐藏的主键列;没有主键的表在定位数据⾏的时候⾮常困难,也会降低基于
⾏复制的效率。
4.禁⽌冗余索引。
索引是双刃剑,会增加维护负担,增⼤IO压⼒。(a,b,c)、(a,b),后者为冗余索引。可以利⽤前缀索引来达到
加速目的,减轻维护负担。
5.禁⽌重复索引。
primary key a;uniq index a;重复索引增加维护负担、占⽤磁盘空间,同时没有任何益处。
6.不在低基数列上建⽴索引,例如“性别”。
⼤部分场景下,低基数列上建⽴索引的精确查找,相对于不建⽴索引的全表扫描没有任何优势,⽽且增⼤了IO
负担。
7.合理使⽤覆盖索引减少IO,避免排序。
覆盖索引能从索引中获取需要的所有字段,从⽽避免回表进⾏⼆次查找,节省IO。INNODB存储引擎中,
secondary index(⾮主键索引,⼜称为辅助索引、⼆级索引)没有直接存储⾏地址,⽽是存储主键值。如果⽤
户需要查询secondary index中所不包含的数据列,则需要先通过secondary index查找到主键值,然后再通
过主键查询到其他数据列,因此需要查询两次。覆盖索引则可以在⼀个索引中获取所有需要的数据,因此效率
较⾼。主键查询是天然的覆盖索引。例如SELECT email,uid FROM user_email WHERE uid=xx,如果uid
不是主键,适当时候可以将索引添加为index(uid,email),以获得性能提升。
8.⽤IN代替OR。SQL语句中IN包含的值不应过多,应少于1000个。
IN是范围查找,MySQL内部会对IN的列表值进⾏排序后查找,⽐OR效率更⾼。
9.表字符集使⽤UTF8,必要时可申请使⽤UTF8MB4字符集。
a)UTF8字符集存储汉字占⽤3个字节,存储英⽂字符占⽤⼀个字节。
b)UTF8统⼀⽽且通⽤,不会出现转码出现乱码⻛险。
c)如果遇到EMOJ等表情符号的存储需求,可申请使⽤UTF8MB4字符集。
10.⽤UNION ALL代替UNION。
UNION ALL不需要对结果集再进⾏排序。
11.禁⽌使⽤order by rand()。
order by rand()会为表增加⼀个伪列,然后⽤rand()函数为每⼀⾏数据计算出rand()值,然后基于该⾏排序,
这通常都会⽣成磁盘上的临时表,因此效率⾮常低。建议先使⽤rand()函数获得随机的主键值,然后通过主键
获取数据。
12.建议使⽤合理的分⻚⽅式以提⾼分⻚效率。
假如有类似下⾯⾯分⻚⻚语句:
SELECT * FROM table ORDER BY TIME DESC LIMIT 10000,10; 这种分⻚⻚⽅⽅式会导致⼤⼤量的io,因
为MySQL使⽤⽤的是提前读取策略。
推荐分⻚⻚⽅⽅式:
SELECT * FROM table WHERE TIMESELECT * FROM table inner JOIN (SELECT id FROM table ORDER BY TIME LIMIT 10000,10) as t
USING(id)
13.SELECT只获取必要的字段,禁⽌使⽤SELECT *。
减少⺴络带宽消耗;
能有效利⽤覆盖索引;
表结构变更对程序基本⽆影响。
14.SQL中避免出现now()、rand()、sysdate()、current_user()等不确定结果的函数。
语句级复制场景下,引起主从数据不⼀致;不确定值的函数,产⽣的SQL语句⽆法利⽤QUERY CACHE。

15.采⽤合适的分库分表策略。例如千库⼗表、⼗库百表等。
采⽤合适的分库分表策略,有利于业务发展后期快速对数据库进⾏⽔平拆分,同时分库可以有效利⽤MySQL
的多线程复制特性。
16.减少与数据库交互次数,尽量采⽤批量SQL语句。
使⽤下⾯的语句来减少和db的交互次数:
a)INSERT ... ON DUPLICATE KEY UPDATE
b)REPLACE INTO
c)INSERT IGNORE
d)INSERT INTO VALUES()
17.拆分复杂SQL为多个⼩SQL,避免⼤事务。
简单的SQL容易使⽤到MySQL的QUERY CACHE;减少锁表时间特别是MyISAM;可以使⽤多核 CPU。【返
回】
18.对同⼀个表的多次alter操作必须合并为⼀次操作。
mysql对表的修改绝⼤部分操作都需要锁表并重建表,⽽锁表则会对线上业务造成影响。为减少这种影响,必
须把对表的多次alter操作合并为⼀次操作。例如,要给表t增加⼀个字段b,同时给已有的字段aa建⽴索引,
通常的做法分为两步:
alter table t add column b varchar(10);
然后增加索引:
alter table t add index idx_aa(aa);
正确的做法是:
alter table t add column b varchar(10),add index idx_aa(aa);
19.避免使⽤存储过程、触发器、视图、⾃定义函数等。
这些⾼级特性有性能问题,以及未知BUG较多。业务逻辑放到数据库会造成数据库的DDL、SCALE OUT、
SHARDING等变得更加困难。
20.禁⽌有super权限的应⽤程序账号存在。
安全第⼀。super权限会导致read only失效,导致较多诡异问题⽽且很难追踪。
21.提交线上建表改表需求,必须详细注明涉及到的所有SQL语句(包括INSERT、DELETE、
UPDATE),便于DBA进⾏审核和优化。
并不只是SELECT语句需要⽤到索引。UPDATE、DELETE都需要先定位到数据才能执⾏变更。因此需要业务提
供所有的SQL语句便于DBA审核。
22.不要在MySQL数据库中存放业务逻辑。
数据库是有状态的服务,变更复杂⽽且速度慢,如果把业务逻辑放到数据库中,将会限制业务的快速发展。建
议把业务逻辑提前,放到前端或中间逻辑层,⽽把数据库作为存储层,实现逻辑与存储的分离。
23.建表语句⽰例

mysql 某列里面的内容去重 mysql去重多个字段_mysql 某列里面的内容去重

24.产品线对应名称说明(供参考)

事业部

命名简写

机票

f

度假

vc

酒店

h

旅⾏

lv

⽆线

wap

⻔票

tkt

兜⾏

dx

旅图

lvtu

搜索

s

ops

ops

⽀付平台

pay

dba

dba

qss

qss

⽕⻋票

t

特殊项目部

sp

呼叫中⼼

cc

⽤户中⼼

uc

市场部

mkt