建表规约

  • 表白是与否概念的字段,必须应用is_xxx命名,数据类型是unsigned tinyint(1-是,0-否)

    • 任何字段如果是非正数,必须是unsigned
    • POJO类中的任何布尔型变量,都不要加is前缀
    • 须要在< resultMap >设置从is_xxx到Xxx的映射关系
    • 数据库示意是与否的值,应用tinyint类型
    • 保持is_ xxx的命名形式是为了明确取值含意和取值范畴
  • 表名,字段名必须应用小写字母(或数字),禁止呈现数字结尾,禁止两个下划线两头只呈现数字.数据库字段名的批改代价很大,因为无奈进行预公布,所以字段名称须要慎重考虑

    • MySQL在windows下不辨别大小写,但在Linux下默认是辨别大小写的
    • 因而,数据库名,表名,字段名,都不容许呈现任何大写字母
  • 表名不应用复数名词

    • 表名应该仅仅示意表外面的实体内容,不应该示意实体数量
    • 对于DAO类名也是复数模式,合乎表白习惯
  • 禁止应用MySQL的官网保留字命名:

    • desc
    • range
    • match
    • delayed
  • 索引命名:

    • pk_字段名: 主键primary key索引
    • uk_字段名: 惟一unique key索引名
    • idx_字段名: 一般index索引名
  • 小数类型为decimal, 禁止应用float,double

    • float和double在存储的时候,存在精度损失的问题,很可能在值比拟时,失去不正确的后果
    • 如果存储的数据范畴超过decimal的范畴,倡议将数据拆分成整数和小数离开存储
  • 如果存储的字符串长度简直相等,应用char定长字符串类型
  • varchar是可变长字符串,不事后调配存储空间,长度不要超过5000

    • 如果长度大于此值,定义字符串类型为text, 独立进去一张表,用主键来对应,防止影响其它字段索引效率
  • 表必备的三个字段:

    • id: 主键,类型为bigint,unsigned,单表时自增,步长为1
    • gmt_create: 类型为datetime,当初时示意被动创立
    • gmt_modified 类型为datetime,过去分词示意被动更新
  • 表的命名最好加上[业务名称_表的作用]
  • 库名与利用名称尽量统一
  • 如果批改字段含意或者对字段的示意状态追加时,须要及时更新字段正文
  • 字段容许适当冗余以进步查问性能,但必须思考数据统一.冗余的字段应遵循:

    • 不是频繁批改的字段
    • 不是varchar超长字段,更不能是text字段

      • 商品类目名称应用频率高,字段长度短,名称根本变化无穷,可在相关联的表中冗余存储类目名称,防止关联查问
  • 单表行数超过500万行或者单表容量超过2GB, 才举荐进行分库分表

    • 如果预计三年后的数据量基本达不到这个级别,不要在创立表时就分库分表
  • 适合的字符存储长度,岂但节约数据库表空间,节约索引存储,更重要的是晋升检索速度

    索引规约

  • 业务上具备惟一个性的字段,即便是多个字段的组合,也必须建成惟一索引

    • 索引不会影响insert的速度,这个速度能够疏忽,但进步查找速度是显著的
    • 即便在应用层做了十分欠缺的校验管制,只有没有惟一索引,必然有脏数据产生
  • 超过三个表禁止join, 须要join的字段 ,数据类型必须相对统一. 多表关联查问时,保障被关联的字段须要有索引
  • 在varchar字段上建设索引时,必须指定索引长度,没必要对全字段建设索引,依据理论文本区分度决定索引长度即可

    • 索引长度与区分度是一对矛盾体

      • 个别对字符串类型数据,长度为20的索引,区分度会高达90%以上
      • 能够应用count(distinct left(列名, 索引长度)) / count(*) 的区分度来确定
  • 页面搜寻严禁左含糊或者全含糊,如果须要要应用搜索引擎来解决

    • 索引文件具备B-Tree的最左前缀匹配个性,如果右边的值未确定,无奈应用此索引
  • 如果有order by的场景,要留神利用索引的有序性 .order by最初的字段是组合索引的一部分,并且放在索引组合程序的最初,避免出现file_sort的状况,影响查问性能

    where a=? and b=? order by c;索引: a_b_c

    要是在索引中有范畴查找,那么索引有序性就无奈利用(WHERE a>10 ORDER BY b; 索引:a_b无奈排序)

  • 利用笼罩索引来进行查问操作,防止回表

    • 比方一本书须要晓得第11章是什么题目,只须要目录浏览一下就更好,这个目录就起到笼罩索引的作用
    • 可能建设索引的品种分为主键索引,惟一索引,一般索引三种,而笼罩索引只是一种查问的成果
    • explain的后果,extra列会呈现: using index
  • 利用提早关联或者子查问优化超多分页场景:

    • MySQL不是跳过offset行,而是取offset+N行,而后返回放弃前offset行,返回N行
    • 当offset特地大的时候,效率就十分低下,要么管制返回的总页数,要么对超过特定阈值的页数进行SQL改写

      • 先疾速定位须要获取的id字段,而后再关联:
      SELECT a.* FROM table1 a,(select id from table1 where condition LIMIT 100000,20) b where a.id=b.id
  • SQL性能优化的指标: 至多要达到range级别,要求是ref级别,最好是consts级别

    • consts: 单表中最多只有一个匹配行(主键或者惟一索引),在优化阶段即可读取到数据
    • ref: 指的是应用一般的索引(normal index)
    • range: 指对索引进行范畴检索

      • explain表的后果,type=index,索引物理文件全扫描,速度十分慢
      • 这个index级别比range还低,但比全表扫描要好的多
  • 建设组合索引的时候,区分度最高的在最右边

    • 如果 where a=? and b=?;如果a列简直靠近于惟一值,只须要单建idx_a索引即可
    • 存在非等号和等号混合时,在建设索引时,等号条件列前置

      • 比方 where c>? and d=?; 即便c的区分度更高,也必须要将d放在索引的最前列,即索引idx_d_c
  • 要留神避免因为字段类型不同造成隐式转换,导致索引生效
  • 创立索引有以下谬误的观点:

    • 认为一个查问就须要建一个索引
    • 认为索引会耗费空间,重大拖慢更新和新增速度
    • 抵制惟一索引,认为业务的唯一性须要在应用层通过"先查后插"的形式解决

      SQL语句规约

  • 不要应用count(列名)count(常量) 来代替count(), count()是SQL92定义的规范统计行数的办法 ,跟数据库无关,跟NULL和非NULL无关

    • count(*) 会统计只为NULL的行
  • count(distinct col) 计算该列出NULL之外的不反复行数,留神 count(distinct col1, col2) 如果其中一列全为NULL, 那么即便另一列有不同的值,也返回0
  • 当某一列的值全是NULL时, count(NULL)的返回后果为0,但sum(col)返回后果为NULL, 因而应用sum要留神NPE问题

    • 应用以下形式来躲避sum的NPE问题:

      SELECT IF(ISNULL(SUM(g)),0,SUM(g)) FROM TABLE;
  • 应用ISNULL来判断是否为NULL

    • NULL与任何值的间接比拟都为NULL:

      • NULL<>NULL的返回后果是NULL,而不是false
      • NULL==NULL的返回后果是NULL,而不是true
      • NULL<>1的返回后果是NULL,而不是true
  • 在代码中写分页逻辑时,若count为0应间接返回,防止执行前面的分页语句
  • 不得应用外键与级联,所有外间的概念必须在应用层解决

    • 比方学生和问题的关系:

      • 学生表中的student_id是主键,那么成绩表中的student_id则为外键
      • 如果更新学生表中的student_id,同时触发成绩表中的student_id更新,即为级联更新
    • 外键与级联更新实用于单机低并发,不适宜分布式,高并发集群
    • 级联更新是强阻塞,存在数据库更新风暴的危险
    • 外键影响数据库的插入速度
  • 禁止应用存储过程,存储过程难以调试和扩大,更没有移植性
  • 数据勘误(数据删除,批改记录操作)时,要先select, 避免出现误删除,确认无误能力执行更新语句
  • in操作能防止就防止,若切实防止不了,须要认真评估in前面汇合元素数量,管制在1000个之内
  • 如果有国际化须要,所有的字符存储与示意,都要以UTF-8编码
  • TRUNCATE TABLEDELETE速度快,且应用的零碎和事务日志资源少,但TRUNCATE无事务且不触发trigger, 有可能造成事变,所以不要应用TRUNCATE语句

    ORM映射规约

  • 在表查问中,一律不要应用 * 作为查问字段列表,须要哪些字段必须明确写明

    • 减少查问分析器的解析老本
    • 增减字段容易与resultMap配置不统一
    • 无用字段减少网络耗费,尤其是text类型字段
  • POJO类的布尔属性不能加is, 而数据库字段必须加is_, 要求在resultMap中进行字段与属性之间的映射

    • 定义POJO类以及数据库字段定义规定,在<resultMap>中减少映射,是必须的
    • 在MyBatis Generator生成的代码中,须要进行对于的批改
  • 不要应用resultClass当返回参数,即便所有类属性名与数据库字段一一对应,也须要定义,每一个表肯定有一个POJO类对应

    • 配置映射关系,使字段与DAO类解耦,方面保护
  • Sql.xml配置参数应用 #{ } 或者 #param#. 不容许应用 ${ }, 这种形式容易呈现SQL注入
  • 不要应用iBATIS自带的queryForList(String statementName, int start, int size)

    • 这个办法的实现形式是在数据库取到statementName对应的SQL语句的所有记录,再通过subList取start,size的子集合
  • 不容许间接应用HashMap与HashTable作为查问后果集的输入

    • resultClass="HashTable",会置入字段名和属性值,然而值的类型不可控
  • 更新数据表记录时,必须同时更新记录对应的gmt_modified字段值为以后工夫
  • 不要写一个大而全的数据更新接口:

    • 不要传入一个POJO类进行更新
    • 执行SQL时,不要更新无改变的字段.一是易出错,二是效率低,三是减少binlog存储
  • @Transactional事务不要滥用:

    • 事务会影响数据库的QPS
    • 应用事务须要思考各方面的回滚计划,包含缓存回滚,搜索引擎回滚,音讯弥补,统计修改
  • < isEqual > 中的compareValue是与属性值比照的常量,个别是数字,示意相等时带上此条件
  • < isNotEmpty > 示意不为空且不为null时执行
  • < isNotNull > 示意不为null时执行