命名规范
库名、表名、字段名、索引
库名、表名、字段名使用驼峰命名。(线上库为大小写敏感)
MySQL有配置参数lower_case_table_names=1,即库表名以小写存储,大小写不敏感。如果是0,则库表名以实际情况存储,大小写敏感;如果是2,以实际情况存储,但以小写比较。
查看MySQL是否大小写敏感:
1 | mysql> show variables like '%case%'; |
库名以【db】开头(暂未遵循)
1 | create database db_xxx default character set=utf8; |
表名以【tbl】开头,如:tblUserMsg
职责相近的表,命名规则应该相同,功能相关的表尽量采用相同的前缀。例如:
1 | tblAtlasAtlas |
字段名以【驼峰】风格命名
索引命名
- 数据表必须有主键,且建议均使用auto_increment的id作为主键(与业务无关),和业务相关的要做为唯一索引,原则上必须定义PRIMARY KEY (
id
)。 - 普通索引以【idx_】开头后面紧跟相关列(idx_col1_col2)
如:KEYidx_msgType_status
(msgType
,status
) - 唯一索引以【uk_】开头(uk_col1_col2 )
如:UNIQUE KEYuk_adminUid_userUid
(adminUid
,userUid
)
命名长度限制
库名、表名、字段名禁止超过32个字符,需见名知意。
临时库、表名须以tmp加日期为后缀(原则上不允许线上创建临时表)
比如tblCrmEcRecord201403。
不具有时间特性的,直接以 tblName01 这样的方式命名。
库、表约束规范
存储引擎
使用Innodb存储引擎
字符集
默认使用utf8字符集(由于数据库定义使用了默认,数据表可以不再定义,但为保险起见,建议都写上)
建表规范
所有表都必须要显式指定主键,每个字段都要有注释,,写明白这个表中存放的数据内容。
例如:
1 | tblUserMsg |CREATE TABLE `tblUserMsg` ( |
关于分表
预估表数据量,如果数据量较大(超过1000w)则需要考虑分表策略。要分表的数据表必须与DBA商量分表策略。
字段定义规范
char、varchar、text等字符串类型
- 对于长度基本固定的列,如果该列恰好更新又特别频繁,适合char
- varchar虽然存储变长字符串,但不可太小也不可太大。UTF8最多能存21844个汉字,或65532个英文
- varbinary(M)保存的是二进制字符串,它保存的是字节而不是字符,所以没有字符集的概念,M长度0-255(字节)。只用于排序或比较时大小写敏感的类型,不包括密码存储
- TEXT类型与VARCHAR都类似,存储可变长度,最大限制也是2^16,但是它20bytes以后的内容是在数据页以外的空间存储(row_format=dynamic),对它的使用需要多一次寻址,没有默认值。
一般用于存放容量平均都很大、操作没有其它字段那样频繁的值。
网上部分文章说要避免使用text和blob,要知道如果纯用varchar可能会导致行溢出,效果差不多,但因为每行占用字节数过多,会导致buffer_pool能缓存的数据行、页下降。另外text和blob上面一般不会去建索引,而是利用sphinx之类的第三方全文搜索引擎,如果确实要创建(前缀)索引,那就会影响性能。凡事看具体场景。
另外尽可能把text/blob拆到另一个表中 - BLOB可以看出varbinary的扩展版本,内容以二进制字符串存储,无字符集,区分大小写,有一种经常提但不用的场景:不要在数据库里存储图片。
int、tinyint、decimal等数字类型
- 使用tinyint来代替 enum和boolean,ENUM类型在需要修改或增加枚举值时,需要在线DDL,成本较高;ENUM列值如果含有数字类型,可能会引起默认值混淆,tinyint使用1个字节,一般用于status,type,flag的列
- 建议使用 UNSIGNED 存储非负数值,相比不使用 unsigned,可以扩大一倍使用数值范围
- int使用固定4个字节存储,int(11)与int(4)只是显示宽度的区别
- 使用Decimal 代替float/double存储精确浮点数,对于货币、金额这样的类型,使用decimal,如 decimal(9,2)。float默认只能能精确到6位有效数字
timestamp与datetime选择
建议字段都定义为NOT NULL
索引定义规范
sql上线,先explain,查看索引使用情况
尽量避免extra列出现:Using File Sort,Using Temporary,rows超过1000的要谨慎上线。
explain解读:
- type:ALL, index, range, ref, eq_ref, const, system, NULL(从左到右,性能从差到好)
- possible_keys:指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用
- key:表示MySQL实际决定使用的键(索引),如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX
- ref:表示选择 key 列上的索引,哪些列或常量被用于查找索引列上的值
- rows:根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数
- Extra
- Using temporary:表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询
- Using filesort:MySQL中无法利用索引完成的排序操作称为“文件排序”
其他索引规范
- 单个索引字段数不超过5,单表索引数量不超过5,索引设计遵循B+ Tree索引最左前缀匹配原则
- 选择区分度高的列作为索引,区分度高的放在前面
- 对字符串使用前缀索引,前缀索引长度不超过8个字符
- 建议优先考虑前缀索引,必要时可添加伪列并建立索引
- 建立的索引能覆盖80%主要的查询,不求全,解决问题的主要矛盾
- DML和order by和group by字段要建立合适的索引
- 避免索引的隐式转换
隐式转换例子,字段定义为varchar,但传入的值是个int,就会导致全表扫描,要求程序端要做好类型检查
字段:remark varchar(50) NOT Null
1 | mysql>SELECT id, gift_code FROM gift WHERE deal_id = 640 AND remark=115127; |
- 避免冗余索引
- 关于主键:表必须有主键 ;不使用更新频繁的列 ;不选择字符串列 ;不使用UUID MD5 HASH ;默认使用非空的唯一键 ,建议选择自增或发号器
- 重要的SQL必须被索引:UPDATE、DELETE语句的WHERE条件列;ORDER BY、GROUP BY、DISTINCT的字段;多表JOIN的字段
- 核心SQL优先考虑覆盖索引
- 不在低基数列上建立索引,例如“性别”
- 不在索引列进行数学运算和函数运算
- 尽量不使⽤外键 ,外键用来保护参照完整性,可在业务端实现;对父亲和子表的操作会相互影响,降低可用性 ;INNODB本身对online DDL的限制
- 不使⽤%前导的查询,如like “%ab”
- 不使用负向查询,如not in/like “无法使用索引,导致全表扫描
最左前缀原则
- mysql使用联合索引时,从左向右匹配,遇到断开或者范围查询时,无法用到后续的索引列
比如索引idx_c1_c2_c3 (c1,c2,c3),相当于创建了(c1)、(c1,c2)、(c1,c2,c3)三个索引,where条件包含上面三种情况的字段比较则可以用到索引,但像 where c1=a and c3=c 只能用到c1列的索引,像 c2=b and c3=c等情况就完全用不到这个索引
尽量不要在频繁更新的列上创建索引
如不在定义了 ON UPDATE CURRENT_STAMP 的列上创建索引,维护成本太高(好在mysql有insert buffer,会合并索引的插入)
SQL设计规范
- 杜绝直接 SELECT * 读取全部字段
- 能确定返回结果只有一条时,使用 limit 1
- 使用like模糊匹配,%不要放首位
会导致索引失效,有这种搜索需求是,考虑其它方案,如sphinx全文搜索 - 涉及到复杂sql时,务必先参考已有索引设计,先explain
- IN的内容尽量不超过200个
- 拒绝大事务
比如在一个事务里进行多个select,多个update,如果是高频事务,会严重影响MySQL并发能力,因为事务持有的锁等资源只在事务rollback/commit时才能释放。但同时也要权衡数据写入的一致性。 - 减少与数据库交互的次数,尽量采用批量SQL语句
- INSERT … ON DUPLICATE KEY UPDATE …,插入行后会导致在一个UNIQUE索引或PRIMARY KEY中出现重复值,则执行旧行UPDATE,如果不重复则直接插入,影响1行。
- REPLACE INTO类似,但它是冲突时删除旧行。INSERT IGNORE相反,保留旧行,丢弃要插入的新行。
- INSERT INTO VALUES(),(),(),合并插入。
- 去掉where 1=1 这样无意义或恒真的条件,如果遇到update/delete或遭到sql注入就恐怖了
事务使用规范
使用场景、原则等。
行为规范
- 杜绝危险SQL
- 大批量更新,如修复数据,避开高峰期,并通知DBA。直接执行sql的由运维或DBA同事操作
- 及时处理已下线业务的SQL
- 复杂sql如多表join,count,group by,主动上报DBA评估。
引用
http://seanlook.com/2016/05/11/mysql-dev-principle-ec/
http://www.cnblogs.com/chenpingzhao/p/5059985.html