zoukankan      html  css  js  c++  java
  • 数据库的规范和SQL优化技巧总结

    现总结工作与平时学习中,关于数据库的规范设计与优化技巧

    1.规范背景与目的

    MySQL数据库与 Oracle、 SQL Server 等数据库相比,有其内核上的优势与劣势。我们在使用MySQL数据库的时候需要遵循一定规范,扬长避短。
    在数据库变更和处理流程、数据库表设计、SQL编写等方面予以规范,从而为业务系统稳定、健康地运行提供保障。
    

    2.设计规范

    说明:
    以下所有规范会按照【高危】、【强制】、【建议】三个级别进行标注,遵守优先级从高到低。
    对于不满足【高危】和【强制】两个级别的设计,强制要求修改。

    2.1数据库设计

    禁止使用的sql语句

    【高危】

    • 禁用update | delete t1 ... where a = xx limit xxx; 这种带limit的更新语句。因为会导致主从不一致,导致数据错乱。
    • 禁止使用关联子查询,如update t1 set ... where name in(select...) 效率极其低下
    • 禁用procedure、function riggerviews event外键约束。因为他们消耗数据库资源,降低数据库实例可扩展性。推荐都在程序端实现。
    • 禁用insert into .. on duplicate key update.. 在高并发环境下,会造成主从不一致。
    • 禁止连表更新语句

    2.1.1 库的创建

    • 【强制】库的名称必须控制在32个字符以内,库名称格式:业务系统名称_子系统名称,同一模块使用的表名尽量使用统一前缀
    • 【强制】创建数据库时必须显式指定字符集,并且字符集只能是utf8或者utf8mb4.创建数据库SQL举例:create database db1 default character set utf8;

    2.1.2 表结构

    1. 【强制】
    • 对于关系表,表名和表名之间尽量体现join的关系,如user和group表直接的关系:x_user_group_xx
    • 表和列的名称必须控制在32个字符以内,表名只能使用字母、数字和下划线,一律小写
    • 表名与模块名强相关,如渠道系统采用“qd_”作为前缀
    • 创建表时必须显式指定字符集为utf8或者utf8mb4
    • 创建表时必须显式指定表存储引擎类型,如无特殊需求,一律为InnoDB。当需要使用除InnoDB/MyISAM/Memory以外的存储引擎时,必须通过审核才能使用。(InnoDB表支持事务、行锁、宕机恢复、MVCC等关系型数据库重要特性,为业界使用最多的MySQL引擎。)
    • 建表必须使用comment 添加注释
    • 中间表用于保留中间结果集,名称必须以tmp_开头。备份表名称必须以bak_开头。
    • 对于超过100W行的数据量大的表进行alter table时,必须在业务低峰期执行。因为alter table 会产生表锁,期间会阻塞对于该表的所有写入,对于业务可能会产生极大影响
    1. 【建议】
    • 核心表须有创建时间和更新时间
    • 表中所有字段加上NOT NULL属性,业务可以根据需要定义DEFAULT值。因为使用NULL值会存在每一行都占用额外存储空间、数据迁移容易出错、聚合函数计算结果偏差等问题
    • 表中有blob、text等大字段,垂直查分到其他表中。
    • 有些字段可以适当冗余,比如user_name,不仅仅存user_id,减少join查询

    2.1.3 列数据类型优化

    1. 【建议】
    • 表中数据值很少的状态status、类型type等字段使用tinytint或者smallint类型节省存储空间
    • 不推荐使用blob,text等类型,比较浪费硬盘和内存空间。
    • 文本数据尽量用varchar存储。因为varchar是变长存储,比char更省空间。一般verchar类型字段树不要超过2700.
    • 时间类型尽量选取timestamp。因为datetime占用8个字节,timestamp占用4个字节

    2.1.4 索引设计

    1. 【强制】
    • InnoDB表必须主键为id int/bigint auto_increment,且主键禁止被更新。
    • 单个索引中每个索引记录的长度不能超过64k
    1. 【建议】
    • 主键的索引以“pk_”开头,唯一索引以“uk_”开头,普通索引以“idx_”开头,一律使用小写格式,以表名/字段的名称或缩写作为后缀。
    • 单个表的索引个数不能超过7个
    • 在建立索引时,多考虑建立联合索引,并把区分度最高的字段方在前面。
    • 在多表关联的join中,保证驱动表的连接列上有索引,这样join执行效率会更高
    • 保证表中互相不存在冗余的索引。

    2.1.5 程序DAO设计

    1.【建议】

    • 对于log或者history类型的表,岁时间增长容易越来越大,因此上线钱DBA必须简历表数据清理或归档方案。
    • 主表机芯增、删、改,从表进行查操作
    • 对于单表读写比大于10:1的数据行或单个列,可以将热点数据放在缓存里(如mechache或redis),加快访问速度,降低MySQL压力。

    2.1.6 规范的建表语句示例

    CREATE TABLE user (
      `id` bigint(11) NOT NULL AUTO_INCREMENT,
      `user_id` bigint(11) NOT NULL COMMENT ‘用户id’
      `username` varchar(45) NOT NULL COMMENT '真实姓名',
      `email` varchar(30) NOT NULL COMMENT ‘用户邮箱’,
      `nickname` varchar(45) NOT NULL COMMENT '昵称',
      `avatar` int(11) NOT NULL COMMENT '头像',
      `birthday` date NOT NULL COMMENT '生日',
      `sex` tinyint(4) DEFAULT '0' COMMENT '性别',
      `short_introduce` varchar(150) DEFAULT NULL COMMENT '一句话介绍自己,最多50个汉字',
      `user_resume` varchar(300) NOT NULL COMMENT '用户提交的简历存放地址',
      `create_time` timestamp NOT NULL COMMENT ‘用户记录创建的时间’,
      `update_time` timestamp NOT NULL COMMENT ‘用户资料修改的时间’,
      `user_review_status` tinyint NOT NULL COMMENT ‘用户资料审核状态,1为通过,2为审核中,3为未通过,4为还未提交审核’,
      PRIMARY KEY (`id`),
      UNIQUE KEY `idx_user_id` (`user_id`),
      KEY `idx_username`(`username`),
      KEY `idx_create_time`(`create_time`,`user_review_status`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='网站用户基本信息';
    
    

    2.2 SQL编写规范

    2.2.1 DML语句

    1. 【强制】
    • select 语句必须指定具体字段名称,禁止写成*。因为select *会将不该读取的数据从mysql里读取处理,造成网卡的压力。且表字段一旦更新,单model没有来得及更新的话,系统会报错。—————sql优化
    • where条件里等号左右字段类型必须一致,否则无法利用索引—————sql优化
    1. 【建议】
    • insert into ... value(xxx), (xxx) ...这里的(xxx)不要超过5000个。值过多虽然上线很快,但会引起主从同步延迟。
    • select语句中不要使用union,推荐使用union all,并且union子句个数限制在5个以内。因为union all不需要去重,节省数据库资源,提高性能。—————sql优化
    • in值列表限制在500以内,这么做事围栏减少底层扫描,减轻数据库压力从而加速查询
    • 事务里批量更新数据需要控制数量,进行必要的sleep,做到少量多次。—————优化
    • where子句中尽量少使用圈模糊的like条件查询,必须有其他等值或范围查询条件,否则无法利用索引—————sql优化
    • 索引列不要使用函数或表达式,否则无法利用索引****—————sql优化
    • 分页查询,当limit起点较高时,可先用过滤条件进行过滤。如select a,b,c from t1 limit 10000,20;优化为: select a,b,c from t1 where id>10000 limit 20;

    2.2.1 多表连接

    1. 【强制】
    • 禁止跨db的join语句,因为这样可以减少模块间的耦合,为数据库拆分奠定坚实的基础
    • 禁止在业务的更新类SQL语句中使用join,比如update t1 join t2..
    1. 【建议】
    • 不建议使用子查询,建议将子查询SQL拆开结合程序多次查询,或使用join来代替子查询—————sql优化
    • 线上环境,多表join不要超过3个表
    • 多表连接查询推荐使用别名,且SELECT列表中要用别名引用字段
    • 在多表join中,尽量选取结果集较小的表作为驱动表,来join其他表

    2.2.3 事务

    1. 【强制】
    • 程序设计必须考虑“数据库事务隔离级别”带来的影响,包括脏读、不可重复度和幻读。线上建议事务隔离级别为repeatable-read
    1. 【建议】
    • 事务中INSERT | UPDATE | DELETE | REPLACE 语句操作的行数控制在2000以内,以及WHERE子句中IN列表的传参个数控制在500以内。
    • 批量操作是,需要控制事务处理隔离时间,进行必要的sleep,一般建议值5-10秒
    • 对于有auto_increment属性字段的表的插入操作,并发需要控制在200以内
    • 事务里包含SQL不超过5个(支付业务除外)。因为过长的事务会导致锁数据较久,MySQL内部缓存、连接消耗过多等雪崩问题。
    • 对于MySQL主从延迟严格敏感的select语句,请开启事务强制访问主库

    2.2.4 排序和分组

    1. 【建议】
    • 减少使用order by,和业务沟通能不排序就不排序,或将排序放到程序端去做。order by、group by、distinct 这些语句较为耗费CPU,数据库的CPU资源是极其宝贵的。—————sql优化
    • order by、group by、distinct这些SQL尽量利用索引直接检索出排序好的数据。如where a=1 order by可以利用key(a,b)。
    • 包含了order by、group by、distinct这些查询的语句,where条件过滤出来的结果集请保持在1000行以内,否则SQL会很慢。

    不断积累中,未完待续...


    若觉得博文不错或对你有帮助,请点击【推荐】或者【关注】,感谢你的支持

    本文来自博客园,作者:黄小葱,转载请注明原文链接:https://www.cnblogs.com/sun-flower1314/p/15242448.html

  • 相关阅读:
    lombok工作原理分析
    jsqlparser和calcite和druid功能对比
    mysql主从备份及常见问题处理
    keepalived结合nginx实现nginx高可用
    FastDFS教程IV-文件服务器集群搭建
    FastDFS教程Ⅲ-文件服务器扩容
    fastDFS教程Ⅱ-文件服务器迁移
    FastDFS教程Ⅰ-文件服务器安装与Nginx配置
    Cognos报表调度与作业管理
    Cognos 11.0快速开发指南 Ⅱ
  • 原文地址:https://www.cnblogs.com/sun-flower1314/p/15242448.html
Copyright © 2011-2022 走看看