MySQL开发规范小节
一、核心原则
1.1 表越窄越好
设计字段的适合,选的的数据类型够用就行
比如:
-
字段ID用来存储事件ID的时候,设计系统中ID最长为30,那么就不需要字段类型设置为varchar(255),尽可能设计一个宅表,而不是宽表。
-
设计Unix时间戳的时候,使用无符号的整性(int unsigned)
-
设计IP地址的时候,使用无符号整性(int unsigned),inet_aotn()和inet_ntoa()函数进行转换实现,而不用chat或varchar
在设计表的同时,查看表的统计信息:
show table status
一般,Avg_row_length这个列超过100个字节的时候,需要看一下是 什么原因导致的,可否优化。
一般,Data_free的值大于0时,表明有碎片。
1.2 表越小越好
设计表的时候,要尽量配合业务需求用尽可能小的数据量或者线上的业务表它的数据量尽可能小,对于热表数据量越小越好,这样IO操作的代价更小,可以通过分库分表,冷热数据分离等方式实现。
建议:表的行数最好不要超过5000W行,尤其是宽表。
一个int类型(4字节)列,在最高达到三层高度的时候,可以存储大约9.7亿条数据。
1.3 请求要高效
每条SQL尽快完成,事务尽快提交/回滚
在修改/删除数据时会锁定数据行,会产生表锁,锁资源没有释放的话,可能造成其他SQL或事务被阻塞。
通过监控MySQL的线程状态和监控InnoDB的事务状态
监控执行事件特别久的SQL或者是长时间没有提交的事务
超过5秒没有执行SQL或事务要发出告警
或者设置修改/锁定行数的阈值大于10行发出告警
检查有没有SQL注入的风险(sleep()函数)
二、细节
2.1 Schema设计原则
-
尽量小的原则
-
不建议使用外键(为了高并发,外键会增加行锁,更大概率导致锁的阻塞和等待事件),如果需要外键保证数据一致性,可以选择在代码层做一些控制。
-
自增int/bigint主键,InnoDB索引表(索引组织表),数据按照具体索引的顺序来进行存储,如果采用char或者uuid做主键或聚集索引,可能会导致数据存储的顺序离散随机,存储时产生大量的磁盘碎片,浪费资源,影响性能。
-
字符集和库表设计要一致,MySQL实例-database-table-schema-function
-
为了MySQL尽量高效
针对单表:
1.单表数据量尽量不要超过5000万
2.单表的物理大小不超过20G
3.索引的数量尽量不超过5个
针对实例:
1.总的大小尽量不超过500G
2.总的表的数量尽量不超过5000个(包括表分区)
2.2 库表字段设计规范
-
每个表字段尽量不超过50个
-
优先使用utf8mb4字符集,因为兼容性最好
1.创建索引:采用utf8mb4字符集影响比较大,用latin1或binary
-
严禁在数据库中明文存储用户的一些核心数据,比如身份证、卡号、密码等,最好单项加密
-
用好int数据类型,金额可以选择扩大n倍存为int或bigint而不是浮点型
-
遇到blob、text字段,尽量拆分出去,然后用主键做关联,避免造成行溢出和碎片风险
-
字符类型尽可能采用varchar的数据类型,灵活高效,尽量不要用加长更新(5个字符更新完变成10个字符)
-
日期的数据类型尽量采用datetime或int类型
2.3 SQL开发建议
-
多表
join
时,join列的数据类型要一致 -
多表
join
时,把过滤后的数据集较小的放在后面作为驱动表 -
在查询的
where
条件中国用上函数索引或表达式索引升级8.0版本 -
尽量不执行
select *
操作 -
尽量不执行
like '%XXX%'
,%之前会扫描全表 -
尽量不使用
!=
,扫描的数据量占到全表的一半左右会默认变成全表扫描 -
能确定结果的返回数量的话,尽量加上limit n(优化器会自动优化,得到结果会停止继续扫描)
-
优先使用union all,替代union ,因为union会自动去重
-
SQL通过SQL审核系统检查后,达到标准再上线
2.4 SQL优化小节
-
最常见的就是where没有索引
-
优先使用主键索引
-
int字段太多,可能会导致索引失效
-
!= 、<> 、is null 、or、in 、not in
,可能会导致索引失效。可用exists替代in,union all实现or功能 -
尽量避免在where子句中进行表达式操作,可能会导致索引失效
-
应尽量避免在where子句中进行函数操作,可能会导致索引失效
-
不要在where子句中
=
的左边进行函数、算术或其他表达式运算,可能会导致索引失效 -
合理使用force index强制使用某个索引,有时效果更好
-
join太多表时,要进行拆分