【MySQL】最容易忽略的常识

起因
  开发反馈一个表的数据大小已经130G,对物理存储空间有影响,且不容易做数据库ddl变更。咨询了开发相关业务逻辑,在电商业务系统中,每笔订单成交之后会有一条对应的订单物流信息,因此需要设计一个物流相关的表用来存储该订单的物流节点信息,该表使用text字段存储物流信息。

大致的表结构:
CREATE TABLE `goods_order_express` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `express_id` int(10) unsigned NOT NULL,
  `message` varchar(200) NOT NULL,
  `status` varchar(20) NOT NULL,
  `state` tinyint(3) unsigned NOT NULL,
  `data` text NOT NULL,
  `created_time` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_expid` (`express_id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4;

业务分析
当快递每到达一个中转站或者发生揽件,接收等事件,快递公司的api都会生成如下格式的信息(去掉业务相关敏感数据) 
[{"time":"2016-03-16 11:16:20","ftime":"2016-03-16 11:16:20","context":"四川省成都市TD客户一公司 已发出,下一站成都转运中心","areaCode":"","areaName":"","status":"在途"},{"time":"2016-03-16 11:11:03","ftime":"2016-03-16 11:11:03","context":"四川省成都市TD客户一公司 已打包","areaCode":"","areaName":"","status":"在途"},{"time":"2016-03-16 11:08:09","ftime":"2016-03-16 11:08:09","context":"四川省成都市TD客户一公司 已揽收","areaCode":"","areaName":"","status":"收件"}]
该json 串 411个字符,开发业务程序去定期轮训调用相关api信息,并把上面的json串数据 insert 或者update 到goods_order_express的data字段。而且该表从开始到现在从未删除,积累了初始到现在的所有数据。随着公司业务爆发式增长,该表未来会更大,而且增长速度会更快。数据库服务器的磁盘空间面临不足,表结构变更难以操作。
如何优化?
1 能否减小数据量写入?
   和业务分析,我们不能丢弃新增的数据。但是每一笔物流信息实际上是有生命周期的,从发货到收件完成即可完成其生命周期,也就是该数据可以不再展示了,我们基本不会查看一个已经收到货的物流信息。因此可以针对历史数据进行归档,比如将90天之前的数据备份到hbase中并且从MySQL 数据库中删除,从而维持该表的大小在一个合理的范围。
2 减少data 字段数据大小
a 缩小json串数据,保留有效数据
time 和ftime 是一样的,和开发确认ftime无功能使用,在我们的物流展示系统中 areaCode areaName也没有逻辑意义。
故对json数据做如下精简 
[{"time":"2016-03-16 11:16:20","context":"四川省成都市TD客户一公司 已发出,下一站 成都转运中心","status":"在途"},{"time":"2016-03-16 11:11:03","context":"四川省成都市TD客户一公司 已打包","status":"在途"},{"time":"2016-03-16 11:08:09","context":"四川省成都市TD客户一公司 已揽收","status":"收件"}]
精简之后占用的字符数由411个减小为237个,减少47%的数据。
b 评估物流节点数
相信大家都有网购的经验 ,一般情况下快递大约含有15-20个节点信息
{"time":"2016-03-16 11:16:20","context":"四川省成都市TD客户一公司 已发出,下一站 成都转运中心","status":"在途"} 占用85个,我们按照100个字符来评估,物流信息最大20*100=2000个字符,使用varchar(2048) 应该可以满足正常需求。
c 可能有人会说凡事总有例外,那我们从这个例外分析一下 如果一个物流有30或者40个节点信息 怎么办?
从深圳到黑龙江漠河 或者新疆乌鲁木齐到杭州,上海的节点信息估计会比较多。对于20个以上 的节点信息 我们不会去关注其中第10个 11个 14个 15个节点的信息。大家对快递的关注点是什么? 商家是否发货?快递公司是否揽件? 快递是否到达目的地的最后1公里。分析到这里,我们可以针对超过25个/30个以上的节点进行收缩处理,去掉中间非核心节点信息,在不影响用户体验的情况下,满足我们的varchar(2048)的设计。
3 分库分表
  这点是迫不得已而为之的方案。现在虽然各种中间件都比较成熟,cobar,oneproxy ,mycat等靠谱的软件,但是对于一个创业公司目前我们还缺少相对应的分布式数据库的管理工具,1024个表如何做变更?这个其实也是一个相对比较困难的问题。

小结 
   经过一系列的分析和优化,我们最终将text字段转化为varchar(2048),发布到线上目前运行良好。回顾上面的优化过程是建立在对业务逻辑和物流相关知识有深入理解,对用户行为多加分析的基础之上的,该过程不需要高深的数据库知识。但是实际上开发往往简单粗暴的接受pd的功能设计理念,而不顾对底层基础架构的影响。其实只需要向前多走一步,我们可以做的更好,只不过这一步,可能是 优秀的程序员的一小步,是某些人的一大步。
留给大家一个问题:如何看待和解决 开发快速迭代带来的技术债?

时间: 2024-09-29 16:14:02

【MySQL】最容易忽略的常识的相关文章

从管理员角度分析:MySQL表引擎中MyISAM和InnoDB的对比

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://dgd2010.blog.51cto.com/1539422/1403785 题记:有些问题只是常识,只是在某些情景下"心急"的管理员可能会忽略这些常识,当然了这也是很多人都会犯的错误.谨以此文记录这件刚才发生的囧事. 常用的MySQL表引擎有不少,但最常用的就是MyISAM和InnoDB,这两者的区别有很多网站上都有很好的文章去介绍,再此仅列出URL就不再赘述. My

判断文本中不存在指定字符串(忽略大小写)的正则表达式的问题

问题描述 判断文本中不存在指定字符串(忽略大小写)的正则表达式的问题 最近遇到个正则表达式的问题,判断不存在指定字符串的正则表达式是这样:((?!MySQL).)*,但忽略大小写判断(?!)加上去后,死活不成功,((?!(?!)MySQL).)*,这个是加上忽略大小后的写法,谁能帮我看看到底是怎么回事 解决方案 ?i 这个应该是忽略大小写的 解决方案二: 谢谢,才发现我写错了,?i写成?!

MySQL关于exists函数使用注意事项

exists语法 SELECT c.CustomerId, CompanyName   FROM Customers c   WHERE EXISTS(    SELECT OrderID FROM Orders o    WHERE o.CustomerID = cu.CustomerID)   这里面的EXISTS是如何运作呢?子查询返回的是OrderId字段,可是外面的查询要找的是CustomerID和CompanyName字段,这两个字段肯定不在OrderID里面啊,这是如何匹配的呢?

CentOS安装MySQL(rpm方式)

    首先你需要下载MySQL安装包,下载地址如下:        http://ftp.ntu.edu.tw/pub/MySQL/Downloads/        这里我以MySQL5.6.26-1.el7版本为例,其中安装包里的x86_64表示是x86架构的64位CPU,其中必须下载的两个安装包为:        MySQL-server-5.6.26-1.el7.x86_64.rpm        MySQL-client-5.6.26-1.el7.x86_64.rpm        

我的MYSQL学习心得(十六) 优化

原文:我的MYSQL学习心得(十六) 优化 我的MYSQL学习心得(十六) 优化 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运算符 我的MYSQL学习心得(六) 函数 我的MYSQL学习心得(七) 查询 我的MYSQL学习心得(八) 插入 更新 删除 我的MYSQL学习心得(九) 索引 我的MYSQL学习心得(十) 自定义存储过程和函数 我的

MySQL数据库my.cnf配置文件注释详

我们知道,在MySQL数据库安装完成后,要对my.cnf配置文件进行适当的修改才能充分利用MySQL数据库的功能.但是对于初学者来说,修改my.cnf配置文件似乎是一个比较难的过程.为了解决这个问题,本文我们对配置文件进行了解释,以方便大家学习参考,希望能够对您有所帮助. 以下是my.cnf配置文件参数解释: [client]   port = 3309  socket = /home/mysql/mysql/tmp/mysql.sock   [mysqld]   !include /home/

mysql总结之explain_php技巧

explain主要用于sql语句中的select查询,可以显示的查看该sql语句索引的命中情况,从而更好的利用索引.优化查询效率.     Explain语法如下:explain [extended] select ... 其中extended是选用的,如果使用的extended,那么explain之后就可以使用show warnings查看相应的优化信息,也就是mysql内部实际执行的query. 列名 描述 说明 相关链接 id 若没有子查询和联合查询,id则都是1. Mysql会按照id从

MySQL关于exists的一个bug_Mysql

今天碰到一个关于exists很奇怪的问题 第一个语句如下: SELECT count(1) FROM APPLY t WHERE EXISTS ( SELECT r.APPLY_ID FROM RECORD r WHERE t.APPLY_ID = r.APPLY_ID ); 产生的结果是:89584 第二个语句如下: SELECT count(1) FROM APPLY t WHERE EXISTS ( SELECT max(r.FINISH_TIME) FROM RECORD r WHERE

mysql中my.cnf 配置 日志类型及文件配置详解

mysql有以下几种日志: 错误日志:    log-err 查询日志:    log 慢查询日志:  log-slow-queries 更新日志:    log-update 二进制日志: log-bin     [client]   port = 3306 socket = /home/mysql/mysql/tmp/mysql.sock   [mysqld]   !include /home/mysql/mysql/etc/mysqld.cnf #包含的配置文件 ,把用户名,密码文件单独存