(一)建表规约
1.【强制】表名、字段名必须使用小写字母或数字,因为数据库字段名的修改代价很大,无法进行预发布,所以字段名称需要慎重考虑。
说明:MySQL在Windows下不区分大小写,但在Linux下默认是区分大小写。
2.【强制】禁用保留字,如desc、delayed等,请参考MySQL官方保留字。
3.【强制】主键索引名为pk_字段名;唯一索引名为uk_字段名;普通索引名则为idx_字段名。
说明:pk_ 即primary key;uk_ 即uniquekey;idx_ 即index的简称。
4.【强制】小数类型为decimal,禁止使用float和double。
说明:float和double在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不正确的结果。
补充:
(1).float和double都是浮点型,而decimal是定点型;float,double等非标准类型,在DB中保存的是近似值,而Decimal则以字符串的形式保存数值。
(2). decimal,整数部分和小数部分是分开存储的,每9个数字占用4个字节,在mysql内部使用的二进制存储,基本没有长度的限制;
(3).浮点型和定点型应用场景: decimal数据类型用于要求非常高的精确度的计算中,其他的一些自然数据,当我们对精度要求不高的时候,可以使用float/double
(4).如果存储的数据范围超过decimal的范围,建议将数据拆成整数和小数分开存储。
5.【强制】如果存储的字符串长度几乎相等,使用char定长字符串类型。
6.【强制】varchar是可变长字符串,不预先分配存储空间,长度不要超过5000,如果存储长度大于此值,定义字段类型为text,独立出来一张表,用主键来对应,避免影响其它字段索引效率。
从存储上讲:
- text 是要要进overflow存储。 也是对于text字段,不会和行数据存在一起。但原则上不会全部overflow ,
会有768字节和原始的行存储在一块,多于768的行会存在和行相同的Page或是其它Page上。
变长字段的缺点:
- 在Innobase中,变长字段,是尽可能的存储到一个Page里,这样,如果使用到这些大的变长字段,会造成一个Page里能容纳的行
数很少,在查询时,虽然没查询这些大的字段,但也会加载到innodb buffer pool中,等于浪费的内存。 (buffer pool
的缓存是按page为单位)(不在一个page了会增加随机的IO)
7.【强制】表必备三字段:id,create_time和update_time。
说明:其中id必为主键,类型为unsigned bigint、单表时自增、步长为1。
8.【推荐】如果修改字段含义或对字段表示的状态追加时,需要及时更新字段注释。
例如:alter table_name add column varchar(*);
COMMENT ON COLUMN table_name IS '注释注释注释注释注释注释注释注释';
9.【推荐**】字段允许适当冗余,以提高查询性能,但必须考虑数据一致。
冗余字段应遵循:
1)不是频繁修改的字段。
2)不是varchar超长字段,更不能是text字段。
正例:商品类目名称使用频率高,字段长度短,名称基本一成不变,可在相关联的表中冗余存储类目名称,避免关联查询。
10.【参考】合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检索速度。
(二)索引规约
1.【强制】业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引。
说明:唯一索引影响insert的速度,这个速度损耗可以忽略,但提高查找速度是明显的;
另外,即使在应用层做了非常完善的校验控制,只要没有唯一索引,总会有一种情况使脏数据产生。
2.【强制】超过三个表禁止join。需要join的字段,数据类型必须绝对一致;
多表关联查询时,保证被关联的字段需要有索引。说明:即使双表join也要注意表索引、SQL性能。
3.【强制】页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。 like本身效率较低
select * fromdoc where title like '%XX' 和 select * fromdoc where title like 'XX%'
4.【强制】索引文件具有B-Tree的最左前缀匹配特性 ,最左侧查询需求,并不是指 SQL 语句的 where 顺序要和联合索引一致。
下面的 SQL 语句也可以命中 (login_name, passwd) 这个联合索引。
select uid, login_time from user where passwd=? andlogin_name=?
5.【推荐】如果有orderby的场景,请注意利用索引的有序性。
orderby最后的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现file_sort的情况,影响查询性能。
/*应当构建索引idx_a_b_c*/
select * from table_name where a=value1 and b=value3 order by c
反例:索引中有范围查找,那么索引有序性无法利用。 如:WHERE a>10 ORDER BY b; 索引 a_b 无法排序。
6.【推荐】利用覆盖索引来进行查询操作,避免回表。
正例:能够建立索引的种类:主键索引、唯一索引、普通索引,而覆盖索引是一种查询的一种效果,用explain的结果,extra列会出现:usingindex。
/*应当构建索引idx_a_b_c*/
select c from table_name where a=value1 and b=value2
7.【推荐】利用延迟关联或者子查询优化超多分页场景。
说明:MySQL并不是跳过offset行,而是取offset+N行,然后返回放弃前offset行,返回N行,
当offset特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过特定阈值的页数进行SQL改写。
正例:先快速定位需要获取的id段,然后再关联:
//select a.* from table_a (select id from table_a where xxx limit no1,no2) b where a.id = b.id
#1
select hotel_seq
from table_name
where id in (select id
from table_name where table_name > 2000000 and id < 2000030)
#2
select hotel_seq from table_name order by id limit 30 offset 2000030
8.【参考】创建索引时避免有如下极端误解:
1)宁滥勿缺。认为一个查询就需要建一个索引。
2)宁缺勿滥。认为索引会消耗空间、严重拖慢更新和新增速度。
3)抵制惟一索引。认为业务的惟一性一律需要在应用层通过“先查后插”方式解决。
(新加)判断方式:在一个读多写少的表中,可以多添加一些索引,但是一个表如果是删除和添加操作较多的时候,就要权衡添加索引是否合适。
(三)SQL语句
1.【强制】不得使用外键与级联,一切外键概念必须在应用层解决。
外键与级联更新适用于单机低并发,不适合分布式、高并发集群;
级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度。
2.【强制】禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。
3.【强制】数据订正时,删除和修改记录时,要先select,避免出现误删除,确认无误才能执行更新语句。
4.【推荐】in操作能避免则避免,若实在避免不了,需要仔细评估in后边的集合元素数量,控制在1000个之内。
5.【参考】如果有全球化需要,所有的字符存储与表示,均以utf-8mb4编码,注意字符统计函数的区别。
说明:
SELECT LENGTH(“轻松工作”);返回为8 (在pgsql中结果为4)
SELECT CHARACTER_LENGTH(“轻松工作”);返回为4
6.【参考】TRUNCATE TABLE比DELETE速度快,且使用的系统和事务日志资源少,
但TRUNCATE无事务且不触发trigger,有可能造成事故,故不建议在开发代码中使用此语句。
说明:
TRUNCATETABLE在功能上与不带WHERE子句的DELETE语句相同。
引用:http://www.matools.com/blog/190441377