MySQL 开发规范【X千万/表级别】
一、MySQL 开发规范概述
原则:SQL开发规范制定是基于良好的编码习惯和可读性;
目的:消除冗余,数据简约,提高效率,提高安全;
范围:《SQL开发规范手册》
二、MySQL 开发规范手册【设计原则】
【1】任何语句使用前通过 EXPLAIN 查看执行计划是否用到索引:【链接】
【2】不要从明细表查统计结果,定期统计插入到汇总表:这个做互联网的深有感触,一张表几千万的数据,统计一个数据,性能真心很低。
1 EXPLAIN
2 SELECT COUNT(user_no) AS u_no,
3 SUM(bid_no) AS b_no
4 FROM user
5 WHERE registered_date >= '2013-02-07 18:11:40';
Query_time: 18.229131 Lock_time: 0.000474 Rows_sent: 0 Rows_examined:100289。
注:从明细表查询时检索记录数为 100289,从汇总表查询时检索记录数为 1,需要改为从汇总表查询。
【3】禁止使用SELECT *,必须指定字段名称,同样,INSERT 后边需要指定字段;
【4】明细统计时,只统计编码,不要关联名称等冗余字段。注:名称显示可查询全局 hashtable(写 300万/秒 读1200万/秒)。
其他 KV工具:Memcached(读写 8万/秒,多线程更快,适合小数据)Redis (读写10万/秒,单线程,可多进程,适合大数据和复杂数据结构)注:一般 php 用 Memcached,Java 用 Redis,小量数据时推荐 static 变量。
【5】联合查询时,每个表必须加别名,否则系统需要自己生成别名,影响性能。关联字段必须是索引(最好是主键),where 条件用以过滤主表;注:提高 SQL 解析效率,便于代码阅读,注意字段前边也要加别名。
1 --问题语句:bid_no 就没有指定别名
2 SELECT a.*, b.user_name
3 FROM user a
4 LEFT JOIN class_name b
5 ON a.uid = b.uid AND b.student = 0
6 WHERE bid_no = '31001383713';
【6】每个查询结果集使用的内存量不要超过 256M,可以通过时间范围控制,如 RK BETWEEN A AND B,大表按可小时操作。注:可通过分批查询返回大量数据;
1 SELECT user_no, bid_no, evaluate_no, registered_date, updated_date, operator, time_stamp FROM user;
2 Query_time: 239.269626 Lock_time: 0.000151 Rows_sent: 2271775 Rows_examined: 2271775
【7】页面查询在 10 秒内要返回结果,服务器超时限制默认为 65 秒。定期查看慢查询日志 xxx-slow.log。注: show variables like '%cache%' 查看 query cache 是否足够大和命中率;
Query_time: 67.432783 Lock_time: 0.000373 Rows_sent: 1 Rows_examined: 168671
【8】语句中避免子查询,子查询无法使用索引(少数子查询使用索引,参考执行计划)。注:子查询结果集记录极少时可以使用,否则效率很差;
【9】语句中避免使用 GROUP BY,可通过批量程序定期汇总。注:频繁 GROUP BY 需要创建临时结果集;
1 SELECT MIN (b.bid_no) FROM user b
2 GROUP BY b.bid_no
【10】禁止语句级并行;
【11】大表 join 用临时表代替 (create temporary table);
三、MySQL 开发规范手册【字段设计】
【1】尽可能使用更小的数据类型,如 TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT。注:int(11) 的11代表客户端显示宽度,并不是取值范围,精度:tinyint -2^8-2^8-1 smallint - 2^15-2^15-1 int -2^31-2^31-1 bigint -2^63-2^63-1;
1 --问题语句:int 类型长度应该根据实际设定
2 DROP TABLE IF EXISTS `user`;
3 CREATE TABLE `user` (
4 `user_no` int(32) NOT NULL DEFAULT '',
5 `bid_no` int(32) NULL DEFAULT NULL,
6 `evaluate_no` int(32) NULL DEFAULT NULL,
7 `registered_date` datetime NULL DEFAULT NULL,
8 `updated_date` datetime NULL DEFAULT NULL,
9 `operator` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
10 `time_stamp` datetime NULL DEFAULT NULL,
11 PRIMARY KEY USING BTREE (`user_no`)
12 ) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
【2】尽量少用 TEXT、BLOB、CLOB 等专有类型 (大数据如图片等可用链接代替),注:CLOB 等类型在性能和兼容性表现不好;
1 --问题语句:after_value_text 字段使用了 CLOB
2 DROP TABLE IF EXISTS `user`;
3 CREATE TABLE `user` (
4 `user_no` int(11) NOT NULL DEFAULT '',
5 `bid_no` int(11) NULL DEFAULT NULL,
6 `evaluate_no` int(11) NULL DEFAULT NULL,
7 `after_value_text` CLOB,
8 PRIMARY KEY USING BTREE (`user_no`)
9 ) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
【3】相同属性对应的数据类型,如字符型,数值型不能混合使用,依赖后期转换;
1 --问题语句:默认bid_no 应该是 int,否则需要隐式转化
2 DROP TABLE IF EXISTS `user`;
3 CREATE TABLE `user` (
4 `user_no` int(11) NOT NULL DEFAULT '',
5 `bid_no` char(11) NULL DEFAULT NULL,
6 PRIMARY KEY USING BTREE (`user_no`)
7 ) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
【4】相同字段不同表中的类型和长度要一致;
【5】字段名称不能使用关键字;
【6】不要指定字段级编码,建议全库统一。可以设置编码的有数据源、表,语句。如果语句中没有设置编码就会遵循表的编码,表的编码不存在时,则遵循数据源的编码,注:字段级编码在导入导出时可能乱码;
【7】默认值要规范,例如日期不要使用 0000-00-00;
1 --问题语句:特有默认值在 ETL 时会导致异常
2 DROP TABLE IF EXISTS `user`;
3 CREATE TABLE `user` (
4 `user_no` int(11) NOT NULL DEFAULT '',
5 `bid_no` int(11) NULL DEFAULT NULL,
6 `time_stamp` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
7 PRIMARY KEY USING BTREE (`user_no`)
8 ) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
【8】不要用自增ID做主键,无法同步,无约束意义。自增在分表分库的业务场景下也不实用,容易导致主键ID冲突。注:字段设计需要精雕细琢,尽量符合三范式,确定没有索引的表可以使用自增主键;
1 --问题语句:user_no 使用了自增
2 DROP TABLE IF EXISTS `user`;
3 CREATE TABLE `user` (
4 `user_no` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID号',
5 `bid_no` int(11) NULL DEFAULT NULL,
6 PRIMARY KEY USING BTREE (`user_no`)
7 ) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
【9】不要使用外键和触发器,注:外键和触发器不适合大数据;
【10】事务相关记录保留时间戳,建议只增不改;在必须对记录进行修改的时候,保留更改时间戳;
1 -- 正确示例:可用于同步和跟踪
2 ctime datetime NOT NULL COMMENT '创建时间',
3 utime timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
【11】精度要求高的字段使用 decimal(number, numeric) 代替 double, float(real)。需要选对场景:精度要求非常高的计算中,要保证有效数字的总个数足够多,需要使用 decimal。注:用在与金额有关的地方;
【12】禁止非英文字段名称,使用中文字段名会创造很多困难点;
四、MySQL 开发规范手册【索引使用】
【1】一般情况下,一次查询只会用到一个索引。特定情况出现 merge index的情况,如下可能出现 ( a=1 or b=2 ) 会合并 a 和 b 的索引,或者使用 union all。因为 or 会破坏索引的最左原则;
【2】每个表索引越少越好,建议1-3个,最多5个 (oltp 1-5,olap 5以上)。注:表索引过多影响操作效率, GreenPlum 数据库可合理利用分区和分布键;
【3】每个查询必须用到索引 (小表可能全表更好,视数据量决定)。注:如果没有索引,即使加了 rownum = 1,也会全表扫描;

【4】建立组合索引时,WHERE 条件中用到等于的字段放前边,用到范围的字段放后边。注:如 DD=100000 AND SJ BETWEEN A AND B 。

【5】删除重复字段的索引,减少 DML IO。注:索引过多影响操作效率,重复索引可能导致执行计划异常;
1 --问题语句:下面的 key 属于重复key 第一个可以删除掉
2 DROP TABLE IF EXISTS `user`;
3 CREATE TABLE `user` (
4 `user_no` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID号',
5 `bid_no` int(11) NULL DEFAULT NULL,
6 PRIMARY KEY USING BTREE (`user_no`),
7 KEY RoadLineID (`bid_no`),
8 KEY RoadLineID2 (`bid_no`,`evaluate_no`)
9 ) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
【6】除了主键外,避免建立其他唯一性索引。注:业务逻辑通过业务应用控制,数据库设计时要选择正确的主键;
1 --问题语句:bid_no 数据量大的话不应该定义为唯一索引
2 DROP TABLE IF EXISTS `user`;
3 CREATE TABLE `user` (
4 `user_no` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID号',
5 `bid_no` int(11) NULL DEFAULT NULL,
6 PRIMARY KEY USING BTREE (`user_no`),
7 UNIQUE KEY index_bid_no (bid_no)
8 ) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
【7】索引中重复的记录数越少,效率越高,效率最高的是主键。注:如果同一记录超过50%,全表扫描定期 analyze table 收集统计信息和直方图,如果可以加 not null 的最好加上。例如性别这个字段就不适合体检索引;
【8】索引字段最好不要存在 NULL,NULL可用 0 替代,建议把默认值设置为 0。注:在 null远多于非null的情况下,建议表设计 default 0;
【9】组合索引可以只使用第一个,或者前两个,或者前几个,不能从第二个开始用,也不能跳着使用。注:索引使用从前缀开始,多字段索引到 between或者<,>等以后字段不会使用索引,排序最好在索引中实现。
【10】 关联查询用到的索引的编码必须一致,建议都采用UTF-8。注:如果编码不一致,索引无效;
五、MySQL 开发规范手册【查询条件】
【1】SQL 语句的 WHERE 条件避免使用无效条件、无效括号、无效排序,如 (1=1)、order by。注:示例语句中使用了无效条件、无效括号,对性能有极大影响;
1 --问题语句:
2 SELECT user_no, bid_no, evaluate_no
3 FROM user
4 WHERE (1=1)
5 AND ( (user_no LIKE '%') AND (bid_no LIKE '%') )
6 AND ( evaluate_no <> 0 )
7 AND ( operator <> 0 )
8 ORDER BY user_no ASC;
9 Query_time: 10.688586 Lock_time: 0.000070 Rows_sent: 55561 Rows_examined: 59075
【2】 SQL语句中不要加用不到的排序。注:类似 order by null 等无效排序会影响执行效率;
【3】控制临时结果集,包括中间结果和中间排序。注:合理横向和纵向拆分,一次处理数据量不要太大;
select * from v$sort_usage,show status like %temp%;、
【4】 WHERE 条件中最好不要用 IN 和 LIKE。注:可使用 exists 代替 in, 使用 = 代替 like;
【5】 WHERE 条件中不要使用 NOW() 等进行判断,避免影响执行计划。注:使用 now() 的存储过程无法重复运行,且影响执行计划。
【6】禁止使用未经认证的 hint,如 SELECT SQL_NO_CACHE f FROM t。注:使用标准SQL,便于版本间兼容;
【7】索引相关字段不要使用函数或者进行运算,如 field1 + 1 = field2、ADDDATE(field1,…CAST。注:大多数字段使用函数不会使用索引,只有确定性 function 使用函数索引;
--问题语句:会导致索引失效
SELECT * FROM user WHERE CAST(CONCAT(updated_date, ' ', time_stamp) AS datetime) BETWEEN '2014-06-10 10:30:00'
【8】禁止字段格式转换,如 SELECT x FROM GS WHERE BM=200000,数值两边不要加引号。注:要区分数值、日期和字符串,科学计数法更要慎重使用;

六、MySQL 开发规范手册【存储过程】
【1】存储过程中操作的记录数超过1000条时不能使用游标 (可用临时表代替,禁止使用触发器、自定义函数)。注:也不能使用 while,大批量数据操作对应脚本必须进行压力测试,以保证可用性;
【2】在存储过程的关键步骤开始和结束都要记录信息到日志表,用于监控和调试。注:提交要及时,记录要详细;
【3】 使用标准操作符,不要使用双引号、!= 等过渡性操作符。注:非标准操作符可能导致其他无法预期问题;
【4】存储过程要能够重复执行,执行时需要清空历史冲突记录。注:非常重要,多种情况下需要存储过程重复运行;
【5】使用自制事务(autonomous transaction)控制写日志,独立日志操作存储过程。注:用以避免回滚时无法记录日志;
【6】所有过程必须定义异常处理,并自定义错误代码,从-20001开始;
1 CREATE OR REPLACE PROCEDURE ap AS
2 BEGIN
3 NULL;
4 --body
5 EXCEPTION
6 WHEN OTHERS
7 THEN
8 NULL;
9 -- exception handler
10 END;

【7】过程避免每条语句提交。注:控制提交频率大于1秒;
【8】禁止使用递归。注:使用递归时,性能消耗无法控制;
七、MySQL 开发规范手册【远程表】
【1】远程表结构要与原始表一致,尤其是索引。注:同时编码要一致;
【2】远程表数据不要大于256M,远程表的 WHERE 无效。注:远程表先下载到本地,再进行其他操作,所以不宜过大;
【3】远程表一般用来全表小数据全量同步。注:远程表大数据操作时很慢;
【4】远程表操作完毕提交操作。注:默认远程表只用来读操作,如果进行写操作,则锁全表;
八、MySQL 开发规范手册【性能优化】
【1】 文件格式改为 XFS 可以提升 5%,增加 1/6 磁盘可以提升 1/6,优化索引和结构,一般可以提升 100-1000 倍。注:了解SQL原理,让数据经过一次读操作即能返回结果时最快;
【2】使用 TYPE=HEAP 的临时表。注:适合频繁删除和更新;
九、MySQL 开发规范手册【引擎使用】
【1】使用 INNODB 引擎操作大批量数据时,在过程结尾提交,避免过度 COMMIT。注:通过事务提交可以提高大数据操作效率,同时有序插入、合并插入也可以大幅提高数据库效率。
1 --正确语句:
2 START TRANSACTION;
3 INSERT INTO t(datetime, UID, content, TYPE) VALUES ('0', 'userid_0', 'content_0', 0),('1',
4 'userid_1', 'content_1', 1);
5 INSERT INTO t(datetime, UID, content, TYPE) VALUES ('2', 'userid_2', 'content_2', 2),('3',
6 'userid_3', 'content_3', 3);
7 COMMIT;

【2】避免跨引擎操作,如表分别为 InnodB 和 MyISAM。问题语句:(不能用函数、需要有索引、先汇总再关联、要查汇总表、表引擎要一致、表编码要一致、字段类型要一致)。注:跨引擎操作时,事务失效,推荐都使用 InnodB;
十 、MySQL 开发规范手册【权限控制】
【1】 PHP 连接 MYSQL 的用户只分配对应库 SIUD。注:权限越大,被攻击时受到的破坏越大。注:权限越大,被攻击时受到的破坏越大;
【2】所有客户端提交的变量都要进行转义操作,防止非法注入。注:可通过工具 AppScan 统一检测;
1 -- 问题脚本:
2 $username = isset($_REQUEST["username"]) ? $_REQUEST["username"] : "";
3 $sql_gh="select EMPID,USERPASS,EMPSTATUS from ydserver.yd_cas_emp where EMPID='$username'";
MySQL 开发规范【X千万/表级别】的更多相关文章
- [转发] 老叶观点:MySQL开发规范之我见
原文: http://imysql.com/2015/07/23/something-important-about-mysql-design-reference.shtml 老叶观点:MySQL开发 ...
- [转载] 根据多年经验整理的《互联网MySQL开发规范》
原文: http://weibo.com/p/2304181380b3f180102vsg5 根据多年经验整理的<互联网MySQL开发规范> 写在前面:无规矩不成方圆.对于刚加入互联网的朋 ...
- 从MySQL开发规范处看创业
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/n88Lpo/article/details/78099185 作者:唐勇.深圳市环球易购.MySQL ...
- 建议收藏 - 专业的MySQL开发规范
为了项目的稳定,代码的高效,管理的便捷,在开发团队内部会制定各种各样的规范 这里分享一份我们定义的MySQL开发规范,欢迎交流拍砖 数据库对象命名规范 数据库对象 命名规范的对象是指数据库SCHEMA ...
- 根据多年经验整理的《互联网MySQL开发规范》
一.基础规范 使用 INNODB 存储引擎 表字符集使用 UTF8 所有表都需要添加注释 单表数据量建议控制在 5000W 以内 不在数据库中存储图⽚.文件等大数据 禁止在线上做数据库压力测试 禁⽌ ...
- 老叶观点:MySQL开发规范之我见
来源:http://ourmysql.com/archives/1396 大多数MySQL规范在网上也都能找得到相关的分享,在这里要分享的是老叶个人认为比较重要的,或者容易被忽视的,以及容易被混淆的一 ...
- 老叶观点:MySQL开发规范之我见(更新版)
转自:http://mp.weixin.qq.com/s?__biz=MjM5NzAzMTY4NQ==&mid=207239419&idx=2&sn=bddbe0a657758 ...
- 《互联网MySQL开发规范》
一.基础规范 使用 INNODB 存储引擎 表字符集使用 UTF8 所有表都需要添加注释 单表数据量建议控制在 5000W 以内 不在数据库中存储图⽚.文件等大数据 禁止在线上做数据库压力测试 禁⽌ ...
- 一份完整的 MySQL 开发规范,进大厂必看!
作者:听风 https://www.cnblogs.com/huchong/p/10219318.html 一.数据库命令规范 1.所有数据库对象名称必须使用小写字母并用下划线分割 2.所有数据库对象 ...
- 一文总结高并发大数据量下MySQL开发规范【军规】
在互联网公司中,MySQL是使用最多的数据库,那么在并发量大.数据量大的互联网业务中,如果高效的使用MySQL才能保证服务的稳定呢?根据本人多年运维管理经验的总结,梳理了一些核心的开发规范,希望能给大 ...
随机推荐
- 前端通过input 输入框实现动态添加行 , 键盘上下左右点击可同步操作中心位置
1. input 代码 ,我们项目组的input封装了,不过不影响使用 通过 @keyup 事件绑定show方法,需要将当前行的信息以及index传递,方便操作 另外要单独给这些需要操作的输入框添加c ...
- 【编程】Python3 使用自定义编码字符表解密Base64数据
前言 Python提供了"base64"模块用于编码.解码Base64数据.但是并不是所有的Base64数据都会使用默认的字符表进行编码,所以这里对Python下实现自定义编码字符 ...
- protobuf协议 待整理
https://blog.51cto.com/wangjichuan/5691192 https://blog.csdn.net/lizhichao410/article/details/126032 ...
- 上分准备 VP Codeforces Round #762 (Div. 3) 4题ABCE
+00:02 +00:16 +01:08 +02:07 VP 情况 4/8 ABCE ,赛时排名可以到823,什么时候我可以上个青 B 本想写个map的二分的,发现自己不会,写了个普普通通的二分 ...
- 阿里云Linux服务器部署JDK8实战教程
下载地址 https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 文件上传 把下载的文 ...
- jsp第十周
数据库test 中建个表 stu(stuid 主键 自动增长 ,用户名,密码,年龄) 1.设计一个注册页面,实现用户注册功能2.设计一个登陆页面,实现用户名密码登陆3.两个页面可以互相超链接 Base ...
- Pintia 7-3 列车调度
7-3 列车调度 (25 分) 火车站的列车调度铁轨的结构如下图所示. 两端分别是一条入口(Entrance)轨道和一条出口(Exit)轨道,它们之间有N条平行的轨道.每趟列车从入口可以选择任意一条轨 ...
- spring java枚举转json 方便前端取值
未处理前: "gender":"GenderEnum.FEMALE(code=2, gender=女)" 解决方法:使用jackson提供的注解 @JsonFo ...
- [C++] epoll server实例
// IO多路复用,事件驱动+非阻塞,实现一个线程完成对多个fd的监控和响应,提升CPU利用率 // epoll优点: // 1.select需要每次调用select时拷贝fd,epoll_ctl拷贝 ...
- (一).JavaScript的简介,变量,数据类型,运算符和表达式
1. JavaScript的简介 1.1 JavaScript概念 JavaScript是一门:动态的 弱类型的 解释型 的脚本语言 1. 动态: 程序执行的时候才确定数据类型 2. 弱类型:数据类型 ...