建表规约
- 表达是否概念的字段,必须使用is_xxx(1-是,0-否)方式命名,unsigned tinyint.
POJO类中,任何布尔类型的变量都不要加is前缀(部分基于方法名的序列化框架,可能引起诸如isA方法和A方法的混淆) - 表名、字段名必须使用小写字母或数字
正例:aliyun_admin,rdc_config,level3_name
反例:AliyunAdmin,rdcConfig,level_3_name - 表名不使用复数
- 主键索引名为pk_字段名;唯一索引名为uk_字段名;普通索引名则为idx_字段名。
- 禁用保留字
- 小数类型为decimal,禁用float和double - 存在精度损失问题。
- 如果存储的字符串长度几乎相等,使用 char 定长字符串类型
- 长度较长(5000)的varchar字段,应定义为text,并独立表存放,避免意向其他字段索引效率
- 表必备三字段:pk_id(bigint unsigned)、create_time(datetime), update_time(datetime)
- 字段允许适当冗余,以提高查询性能,但必须考虑数据一致
- 不是频繁修改的字段
- 不是唯一索引字段
- 不是varchar超长字段,更不能是text字段
- 采用合适的字符存储长度,无符号数必带unsigned参数
索引规约
- 业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引
- 超过三个表进制join. 需要join的字段,数据类型保持绝对一致。 join关联的列应该有索引(即使双表join,也应注意性能)
- 对于varchar字段建立索引,应该指定索引长度
- 页面搜索严禁左模糊或全模糊,违反最左匹配原则,会导致全表查询
- 对于order by的场景,最后的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能
正例:where a=? and b=? order by c; 索引:a_b_c
反例:索引如果存在范围查询,那么索引有序性无法利用,如:WHERE a>10 ORDER BY b; 索引a_b无法排序。 - 利用覆盖索引,避免回表
- 利用延迟关联或者子查询优化超多分页场景
正例:SELECT t1.* FROM table1 as t1, (select id from 表 1 where 条件 LIMIT 100000,20 ) as t2 where t1.id=t2.id
正例:SELECT t1.* FROM table1 as t1 where ti.id >= 90000 LIMIT 10;
- SQL性能优化,至少要达到range级别,要求是ref级别。
- 建立组合索引,应把散列度大的放在最前列,但是也要考虑范围查询和单值查询
- 避免隐式转换,导致索引失效
SQL语句
- 不要使用count(列名)或count(常量)来替代count(*),count(*)是SQL92的标准,会统计值为NULL的行。
- count(distinct col)计算该列除NULL之外的不重复行数,注意count(distinct col1,col2)如果其中一列全为NULL,那么即使另一列有不同的值,也返回为0
- 当某一列的值全是NULL时,count(col)的返回结果为0,但sum(col)的返回结果为NULL,因此使用sum()时需注意NPE问题
SELECT IFNULL(SUM(column), 0) FROM table;
- 使用ISNULL()判断是否为NULL值,NULL与任何值的比较都为NULL --- ISNULL(column)的执行效率比is null更快
- 代码中写分页查询逻辑时,若 count 为 0 应直接返回,避免执行后面的分页语句。
- 不得使用外键与级联,一切外键概念必须在应用层解决,禁止使用存储过程
- 数据订正(特别是删除或修改记录操作)时,要先select,避免出现误删除,确认无误才能执行更新语句。
- 对于数据库中表记录的查询和变更,只要涉及多个表,都需要在列名前加表的别名(或表名)进行限定 --- 避免日后新增字段可能出现的冲突
ORM映射
- 表查询时,一律不要使用 * 作为查询的字段列表,需要哪些字段必须明确写明
- 增加解析成本
- 增减字段容易与resultMap配置不一致
- 无用字段传输占用网络资源
- 不要用resultClass当返回参数,即使所有类属性名与数据库字段一一对应,也需要定义<resultMap>,反过来,每一个表也必然有一个<resultMap>与之对应。
- 配置映射关系,使字段与 DO 类解耦,方便维护 - 不允许直接拿 HashMap 与 Hashtable 作为查询结果集的输出