MES案例研究1 - 大表并发查询

某工厂是生产数码产品金属外壳的,每天近100万件的产量,随着圣诞节的临近,客户订单大量增加,但是生产却跟不上,经初步分析,发现问题发生在激光雕刻二维码的工位,由于镭雕机从MES取号的时间太长,造成生产的瓶颈。

该厂MES的主要功能是做生产追溯,包括:生产过程记录、关键工位检查、质量问题收集等。

在镭雕工位,客户端程序要从MES中查询得到对应机型的最小序列号,然后传给镭雕机。

查询SQL的核心逻辑为:


SELECT

MIN(serial_number)

FROM

t_product_history t

WHERE t.type = ‘PN1’ //产品类型

AND t.status = 1;    //产品状态,1表示尚未镭雕

通过ORACLE AWR可以得到此查询SQL在某个时间段的总执行时间。

此外,我们可以查询得到SQL_TEXT的执行次数。

两者相除,就得到此SQL的平均时间:竟然达到2秒!

更糟糕的是,查看客户端代码后,发现没有做并发处理,当现场二十多台镭雕机同时工作时,工人一旦发现响应慢,就会不断点击手动请求按钮,造成多并发,进而造成查询的执行时间更长。

接下来只有认真地分析t_product_history这个表的业务。

这个表是一个产品的生产历史记录表,整个生产过程中大约要经过近100个采集工位,每件产品经过每个工位时会在此表中新增一条记录,这样一天100万件产品就要新增近1亿条记录,表容量相当地大。

这个表也做了分区处理,是按月分区的,但是查询SQL的WHERE条件(产品类型和状态)并没有利用分区字段,所以系统会从索引中扫描记录,而索引没有做分区,而索引的容量也已经非常巨大了,这样的后果是每次查询都要扫描数百亿条记录,自然效率低了。

其实数据库里还有另一个表t_product_status,用于表示产品的状态,数据容量要小得多,但自从工单下发后,状态值就为1了,一直到完工变成状态2,所以不能从此表中得到尚未镭雕的最小序列号。

在不更改这两表功能的前提下,只有另辟蹊径了。

首先我们分析生产的特性:大批量少品种,每个工单对应一种产品,每个工单的量都非常大,一般都在几万至几十万的量,每个工单下发后,在镭雕工位做连续生产,中间不会跳序列号。

因此,我们可以把镭雕要取的最小序列号抽象成符合条件的工单的一个特征,一个中间量的指针值。

首先建一个工单的扩展属性表t_wo_pointer,定义以下属性:工单号,产品类型,状态,数量,最小序列号,当前指针值,当前序列号。

当工单下发时,在原存储过程中增加一个小的逻辑,即在此扩展表中增加一条记录,将状态置为1表示尚未镭雕,并计算得到最小序列号,并置指针值为0。

在镭雕工位,查询的SQL更改为:


SELECT

MIN(Current_sn), //当前序列号

Pointer         //当前指针值

FROM

t_wo_pointer

WHERE t.type = ‘PN1’ //产品类型

AND t.status = 1;    //产品状态,1表示尚未镭雕

这样就查询得到了符合条件的最小序列号和指针值。

将序列号输出,然后将指针值加1并更新当前序列号,如果指针值=工单数量则将工单的状态改为2。

然后加上并发事务处理。

经过这番处理后,并没有改动业务逻辑,但是查询的时间从原来的2秒变成只有1.8微秒(要查询的表只有100多条记录),当即解决了此处瓶颈,提升了8%的产能,帮助工厂顺利完成了圣诞节的订单。

我从此案例学到的教训是:

  1. 大表查询要慎重。
  2. 尽可能不要在历史记录表中执行生产现场控制的逻辑。
  3. 大表做了分区以后,分区字段不一定会被查询语句利用到,而大表的索引不一定做了分区处理。
  4. 连续数字、序列号可以考虑用指针表的方式处理,前提是要做好并发事务处理。
时间: 2024-11-11 21:11:22

MES案例研究1 - 大表并发查询的相关文章

Mysql大表查询优化技巧总结及案例分析

http://www.169it.com/article/3219955334.html sql语句使用基本原则:1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引.2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: select id... sql语句使用基本原则: 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2

PLSQL_Oracle外部表的概念和使用(案例)(通过外部表直接查询数据文件以节数据库表空间)

2014-08-25 BaoXinjian 一.摘要 ORACLE外部表用来存取数据库以外的文本文件(Text File)或ORACLE专属格式文件. 因此,建立外部表时不会产生段.区.数据块等存储结构,只有与表相关的定义放在数据字典中. 外部表,顾名思义,存储在数据库外面的表. 当存取时才能从ORACLE专属格式文件中取得数据,外部表仅供查询,不能对外部表的内容进行修改(INSERT.UPDATE.DELETE操作). 不能对外部表建立索引.因为创建索引就意味着要存在对应的索引记录.而外部表其

PLSQL_Oracle分区表和相应的分区索引管理和使用(案例)(创建交易表等大表时进行分区提高效率)

2014-08-22 BaoXinjian 一.摘要 1.分区表: 随着表的不断增大,对于新纪录的增加.查找.删除等(DML)的维护也更加困难.对于数据库中的超大型表,可通过把它的数据分成若干个小表,从而简化数据库的管理活动.对于每一个简化后的小表,我们称为一个单个的分区 对于分区的访问,我们不需要使用特殊的SQL查询语句或特定的DML语句,而且可以单独的操作单个分区,而不是整个表.同时可以将不同分区的数据放置到不同的表空间,比如将不同年份的销售数据,存放在不同的表空间,即年的销售数据存放到TB

如何应付表数据过大的查询问题?(如何尽量避免大表关联)

原文:如何应付表数据过大的查询问题?(如何尽量避免大表关联) 一般来说,对于做B/S架构的朋友来说,更有机会遇到高并发的数据库访问情况,因为现在WEB的普及速度就像火箭升空,同时就会因为高访问量带来一系列性能问题,而数据库一直是用户与商人之间交流的重要平台.用户是没有耐心忍受一个查询需要用上10秒以上的,或者更少些,如果经常出现服务器死机或者是报查询超时,我想那将是失败的项目.做了几年的WEB工作,不才,一直没有遇到过大访问量或者是海量数据的情况.这里并不是说没有海量数据的项目就不是好项目,要看

form表单数据量很大时的查询和保存

目标:本周做了一个300多项的form表单查询和保存. 思考:之前做查询和保存,用的是提交后同步跳转:这次想使用不同的方式来做:采用了ajax异步查询和保存试试. 过程: 选择jQuery中的ajax函数和spring mvc框架,数据交互采用json形式 先写后台,类用了注解 @Controller@RequestMapping("/baController") 方法用了注解 @RequestMapping(value="/queryba.do", produce

好程序员大数据学习路线之hive表的查询

好程序员大数据学习路线之hive表的查询 1.join 查询 1.永远是小结果集驱动大结果集(小表驱动大表,小表放在左表). 2.尽量不要使用join,但是join是难以避免的. left join . left outer join . left semi join(左半开连接,只显示左表信息) hive在0.8版本以后开始支持left join left join 和 left outer join 效果差不多 hive的join中的on只能跟等值连接 "=",不能跟< &g

mysql 多表分类查询 好大上啊!

一.三张表进行查询 二.两张表通过范围查

表连接查询与where后使用子查询的性能分析。

子查询就是在一条查询语句中还有其它的查询语句,主查询得到的结果依赖于子查询的结果. 子查询的子语句可以在一条sql语句的FROM,JOIN,和WHERE后面,本文主要针对在WHERE后面使用子查询与表连接查询的性能做出一点分析. 对于表连接查询和子查询性能的讨论众说纷纭,普遍认为的是表连接查询的性能要高于子查询.本文将从实验的角度,对这两种查询的性能做出验证,并就实验结果分析两种查询手段的执行流程对性能的影响. 首先准备两张表 1,访问日志表mm_log有150829条记录(相关sql文件已放在

详解MySQL大表优化方案

当MySQL单表记录数过大时,增删改查性能都会急剧下降,可以参考以下步骤来优化: 单表优化 除非单表数据未来会一直不断上涨,否则不要一开始就考虑拆分,拆分会带来逻辑.部署.运维的各种复杂度,一般以整型值为主的表在千万级以下,字符串为主的表在五百万以下是没有太大问题的.而事实上很多时候MySQL单表的性能依然有不少优化空间,甚至能正常支撑千万级以上的数据量: 字段 尽量使用TINYINT.SMALLINT.MEDIUM_INT作为整数类型而非INT,如果非负则加上UNSIGNED VARCHAR的