数据库命名规范

  • 数据库对象名称使用小写字母并用下划线分割
  • 名称禁止使用MySQL保留关键字
  • 命名见名识义,长度不能太长
sc_userdb    数据库    user_account    账户表
  • 临时表 tmp为前缀, 日期后缀
  • 备份表 bak前缀, 日期后缀
  • 储存相同数据的列名和数据类型要一致
关联列查询, 数据类型不一致时会转换, 造成性能大幅下降

数据库基本设计规范

  • 使用Innodb存储引擎
5.6版本以后成为了默认引擎
支持事务, 行级锁, 更好的恢复性, 高并发性能更好
  • 数据库和表的字符集要统一 UTF8
utf8字符集 单个汉字占用3个字节, ASCII码占用一个
  • 表和字段添加注释
  • 尽量控制单表数据量大小, 建议在500万内
500万并不是数据库限制
历史数据归档, 分库分表
  • 谨慎使用Mysql分区表
分区表在物理上存储在多个文件, 逻辑上表现为一个
谨慎选择分区键, 跨分区查询效率很低
使用物理分表管理大数据
  • 数据冷热分离, 减小表的宽度
mysql限制最多4096列,每行数据大小不超过65535字节 ??
作用: 减少磁盘io, 保证热数据的内存缓存命中率
利用缓存, 避免读入无用冷数据 (select *)
经常一起使用的列放入一个表中, 避免过多的关联查询 (垂直拆分列)
  • 禁止在表中建立预留字段
预留的字段难以做到 见名识意
无法准确确认 储存的数据类型
后期对字段类型修改时会对 全表锁定
  • 禁止在数据库中储存图片, 文件 等二进制数据
高磁盘io
  • 禁止在线上做数据库压力测试(上线后)
  • 禁止从开发测试环境直接连接生产环境数据库

数据库索引规范

查询时通过索引, 减少随机IO, 增加查询性能,过滤完的数据越少,要读的就越少
  • 避免建立冗余,重复的索引,单张表建议5个
如果存在多个索引, MySQL在执行查找时, 会评估哪个是最佳方案 索引太多会加长MySQL优化器生成查询计划的时间, 影响了查询效率
索引可以增加查询效率, 但是会降低插入和更新的效率
innodb表中需要主键, 不能使用频繁更新的列作为主键, 不使用uuid MD5 hash 字符串作为主键 
innodb是索引组织表, 数据的逻辑储存顺序按照主键索引排列
主键值频繁更新会使数据的逻辑顺序频繁变动, 造成大量IO操作
uuid md5 hash 不能保证顺序增长,为了保持索引的顺序,插入小的值会插在中间,后面的全部后移,造成大量io操作
主键建议使用单独列自增ID
  • 常见索引建议
    select update delete 语句的 where 从句中的列
    order by, group by, distinct 中的字段
    如果上述从句和order by等中的字段有多个,并不要给每一列都上索引,建立联合索引更好
    多表join查询的关联列上的索引: MySQL的join查询是嵌套循环,如果没有索引效率很差
  • 索引列的顺序
区分度最高的在最左侧,比如主键,唯一索引,区分度为1,每个值都不一样,通过主键查找,更新数据的性能是最高的
字段长度小的列 往左排,字段长度越小,每一"页"储存的列就越多,数据量越大,io性能越好
以上俩点相似的,把使用最频繁的列放在左侧
  • 对频繁的查询优先使用覆盖索引
覆盖索引是包含了所有要查询字段的索引
可以避免innodb表进行二次查找, 二级索引保存的是行的主键信息, 通过主键二次查询获取信息
覆盖索引包含了所需的信息,避免二次查找
覆盖索引按照键值顺序存储,读取时候就变成了顺序io,增加效率
  • 尽量避免使用外键
避免使用外键约束,但是要建立外键索引=》关联列的索引
外键的作用是保证数据的完整性(主表与子表)一致性,一条数据在主表中存在,才能在子表中存在
在每次写操作时都要检查外键约束是否成立,降低性能
数据的一致性建议用其他方法保证

数据库字段设计规范

字段类型会直接影响数据库的性能,影响索引的建立:
字段越大,索引占用空间也越大,一个页中所能存下的索引也越少,索引变差
  • 优先选择符合储存需要的最小的数据类型
非负整数采用无符号整形存储,无符号最大值比有符号多一倍
将字符串转为数字类型存储
例如IP转为数字类型
inet_aton()        # a to n
inet_ntoa()        # n to a

 varchar(N) N代表字符,可储存N个中文字,不是字节
 过大的长度会消耗更多的内存:物理存储时按实际使用长度,读取时按字段设置长度读取到内存
  • 避免text,blob
不支持内存临时表,只能用磁盘临时表,还会造成二次查询
把blob,text分离到单独的扩展表中,避免select *
只能使用前缀索引,不能有默认值
  • 谨慎使用媒体类型 ENUM
其它关系型数据库中并不存在这种类型
优点:本身是字符串类型,但是以整形存储,最多可以存储65535种媒体值
缺点: 
修改媒体类型的值需要使用alter语句,会生成元数据锁,造成堵塞
排序效率低:排序前需要先转换,把媒体值转为字符串再排序=》无法使用索引
ENUM不要储存 整型媒体值
  • 尽可能把列定义为NOT NULL
在这种列上建立索引,在索引上会额外储存一个状态空还是非空,占用索引的空间
进行比较和计算时要对null值做特别的处理, 可能使索引失效
  • 使用 timestamp datetime来储存时间
timestamp 存储范围小 1970 ~ 2038年
timestamp 实际上是int存储 但可读性更高
超出timestamp范围的,使用datetime
  • 金额使用 decimal 精确类型
计算时不丢失精度, 适用金额
占用空间是由定义的宽度决定的,每4个字节可以存9个数字,小数点占用一个字节
可以存储比 bigint 更大的 整型 数据

数据库SQL开发规范

  • 在程序中建议使用预编译语句进行数据库操作
一次解析多次使用,只传参数,比传sql语句更高效
防止sql注入
  • 避免数据类型的隐式转换
一般在where从句中,当列类型和参数类型不一致时,会发生隐式转换
导致索引失效
  • 充分利用表上存在的索引
避免使用 %a% 或者 %a 进行模糊查找,a%可以使用到索引
一个sql只能利用到联合索引中的一列进行范围查询,那么这一列要放在联合索引的右侧,否则这一列右面的索引不会被用到了
使用 left join 或 not exists 来代替 not in操作,not in一般会使索引失效
  • 程序使用不同数据库要使用不同的账号,禁止跨库查询
给数据库迁移和分库分表留出余地
降低业务耦合度
避免权限过大产生安全风险
  • 禁止使用select *查询
如果字段里有text等类型,会二次读取出来
消耗更多的cpu和io资源
无法使用覆盖索引
减少表结构带来的影响
  • 禁止在使用insert语句时不指定字段
insert into test(a,b,c) values(1,2,3);
  • 避免使用子查询, 把子查询优化为 join操作
子查询产生临时表, 无法使用索引,如果结果集数据量越大影响越大
临时表消耗过多的CPU和IO资源
  • 避免关联过多的表
关联的表占用内存 (join_buffer_size)
关联操作会产生临时表
MySQL最多关联61个表 建议不超过5个
  • 减少同数据库的交互次数
数据库更适合批量处理操作 ( 分页 )
合并多个相同的操作 (比如 alter修改表 )
  • 使用in 代替 or ->在同列判断时
in操作可以使用到索引
in的数量不要超过500个
  • 禁止使用order by rand()
会把所有符合条件的数据加载到内存中, 再排序
消耗大量的CPU io 内存资源
建议使用程序取随机值
  • 禁止在where 从句中 对列进行函数转换或计算
会导致无法使用索引  (time问题)
  • 在明显不会重复时, 使用union all 不使用 union
union会把所有数据放到临时表中去重
union all 不会去重
  • 合理的拆分大sql为多个小sql
一个sql只能用一个cpu进行计算,
拆分后可以通过并行执行来提高处理效率

数据库操作行为规范

  • 超过百万行的批量写操作,分批多次进行操作
大批量操作会造成严重的主从延迟
binlog日志为row格式时会产生大量的日志
避免产生大事务操作
  • 大表的结构修改使用工具
大表数据结构的修改会造成严重的锁表操作
pt-online-schema-change  工具
  • 禁止给程序使用的账号赋予super权限
数据库维护的权限
当达到最大连接数时,允许一个有super权限的用户连接
  • 程序连接数据库账号,遵循权限最小原则
只能在一个DB下使用,禁止跨库
原则上不赋予drop权限