这几天在写一个存储过程,反复优化了几次,从最开始的7分钟左右,优化到最后的几秒,并且这个过程中我的导师帮我指点了很多问题,这些指点都是非常宝贵的,独乐乐不如众乐乐,一起来分享这次的优化过程吧。

这个存过程的需求是这样的,抓取某个时间段内的订单明细,然后计算并汇总到某表即可。

于是乎,我写出第一版的存储过程,代码如下:

  /******************************************/
/* 合并当前版本时间段内MO的维修换料需求 */
/* p_begin 起始时间 */
/* p_user 创建人 */
/* p_version 版本编码 */
/* p_version 需求版本头表id */
/* Created by wufei in 2013-10-29 */
/******************************************/
procedure clc_Mat_Addition_Require(p_begin date,
p_user varchar2,
x_result out varchar2,
x_msg out varchar2) is
v_count int; --处理行数
v_num number; --维修换料数
v_version_code mms_mo_ori_version.version_code%type; --版本号
v_version_id mms_mo_ori_version.version_id%type; --需求单头号
v_raise exception;
begin
v_version_code:=to_char(p_begin,'yyyyMMdd');
v_version_id := fun_mms_get_guid();
--查询历史版本表,已执行过不允许执行
select count(*) into v_count from mms_mo_ori_version mmov
where mmov.version_code = to_char(p_begin,'yyyyMMdd'); if v_count>0 then
raise v_raise;
end if; v_count:=0;
--生成新版本头数据
insert into mms_mo_ori_version
(version_id,
version_code,
start_time,
end_time,
creation_date,
created_by,
mat_type)
values
(v_version_id,
v_version_code,
p_begin,
p_begin+1,
sysdate,
p_user,
1);--类别:维修换料 for line in (
select cwr.inventory_item_id,cwr.item_code,cwr.description,sum(cwr.quantity_open) as quantity_open
from ifce.cux_wip_requirement_v cwr,
ifce.cux_wip_entity_all_v cwal
where cwr.WIP_ENTITY_ID = cwal.WIP_ENTITY_ID
and cwal.START_DATE >= p_begin
and cwal.START_DATE < p_begin+1
and cwr.quantity_open > 0
group by cwr.INVENTORY_ITEM_ID,cwr.item_code,cwr.description
)
loop --获取维修换料数
select ifce.wip_logistics.fun_get_Iqcquit_sum(line.ITEM_CODE,trunc(p_begin))
into v_num from dual;
if (v_num >0) then --当维修换料需求比例数大于0时插入
insert into mms_mo_mat_require
(mat_requireid,
mat_id,
mat_code,
mat_desc,
require_time,
require_qty,
status,
creation_date,
created_by,
version,
mat_type,
super_market_inv_code)
select fun_mms_get_guid(),
line.inventory_item_id,
line.item_code,
line.description,
p_begin,
line.quantity_open*v_num,
'',
sysdate,
p_user,
v_version_code,
1,
'42B'
from dual;
v_count:=v_count+1;
end if; end loop; commit;
x_result:='Y';
x_msg:=to_char(v_count);
exception
when v_raise then
x_result:='N';
x_msg:='当前日期已执行过维修换料运算。';
when others then
rollback;
x_result:='N';
x_msg:='程序异常';
end clc_Mat_Addition_Require;

代码是没有问题,运行结果也没有问题,但就是慢,经过导师指点,“cwr.WIP_ENTITY_ID = cwal.WIP_ENTITY_ID”这里是有问题,这两个表之间用这种方式连接,索引会不起作用,并且这个表的时间没有加索引,综合起来就比较慢了,大概需要7秒才能运行完成。

找到了问题之后,就开始了改写。

改写的逻辑是这样的:

1,首先不使用这种连接方式,并且从另外一个本地表中用时间做过滤,这个时间是有索引的。

2,从车间排程表中,查询出需要运行的单据,并遍历。

3,遍历单据的明细。

4,插入维修换料数据。

5,对已插入的维修换料数汇总。

改写之后代码如下:

  /******************************************/
/* Mo维修换料需求运算 */
/* p_begin 起始时间 */
/* p_user 创建人 */
/* p_version 版本编码 */
/* p_version 需求版本头表id */
/* Created by wufei in 2013-10-29 */
/******************************************/
procedure clc_Mat_Addition_Require3(p_begin date,
p_user varchar2,
x_result out varchar2,
x_msg out varchar2) is
v_count int; --处理行数
v_num number; --维修换料数
v_version_code mms_mo_ori_version.version_code%type; --版本号
v_version_id mms_mo_ori_version.version_id%type; --需求单头号
v_raise exception;
v_wareHouse mms_dictionary_item.input_code1%type; --补料仓代码
begin
v_version_code:=to_char(p_begin,'yyyyMMdd');
v_version_id := fun_mms_get_guid();
--查询字典表里的补料仓代码
select mdi.input_code1 into v_wareHouse from mms_dictionary_item mdi
where code='AdditionWarehouse';
--查询历史版本表,已执行过不允许执行
select count(*) into v_count from mms_mo_ori_version mmov
where mmov.version_code = to_char(p_begin,'yyyyMMdd'); if v_count>0 then
raise v_raise;
end if; v_count:=0;
--生成新版本头数据
insert into mms_mo_ori_version
(version_id,
version_code,
start_time,
end_time,
creation_date,
created_by,
mat_type)
values
(v_version_id,
v_version_code,
p_begin,
p_begin+1,
sysdate,
p_user,
1);--类别:维修换料 for line in (
select wdps.wip_entity_id
from mms_wdps wdps
where wdps.plan_date >= p_begin
and wdps.plan_date <= p_begin+1
)
loop
for detailLine in (
select cwr.inventory_item_id,cwr.item_code,cwr.description,sum(cwr.quantity_open) as quantity_open
from ifce.cux_wip_requirement_v cwr
where cwr.WIP_ENTITY_ID = line.wip_entity_id
and cwr.quantity_open > 0
group by cwr.INVENTORY_ITEM_ID,cwr.item_code,cwr.description
)
loop
--获取维修换料数
select ifce.wip_logistics.fun_get_Iqcquit_sum(detailLine.ITEM_CODE,trunc(p_begin))
into v_num from dual;
if (v_num >0) then --当维修换料需求比例数大于0时插入
insert into mms_mo_mat_require
(mat_requireid,
mat_id,
mat_code,
mat_desc,
require_time,
require_qty,
status,
creation_date,
created_by,
version,
mat_type,
super_market_inv_code)
select fun_mms_get_guid(),
detailLine.inventory_item_id,
detailLine.item_code,
detailLine.description,
p_begin,
detailLine.quantity_open*v_num,
0,
sysdate,
p_user,
v_version_code,
5,--将Mat_type改为5,稍后过滤,汇总
v_wareHouse
from dual;
v_count:=v_count+1;
end if;
end loop;
end loop;
commit;
--将当天插入的维修换料汇总
insert into mms_mo_mat_require
(mat_requireid,
mat_id,
mat_code,
mat_desc,
require_time,
require_qty,
status,
creation_date,
created_by,
version,
mat_type,
super_market_inv_code)
(select fun_mms_get_guid(),
mat_id,
mat_code,
mat_desc,
p_begin,
sum(require_qty) as qty,
0,
sysdate,
p_user,
v_version_code,
1,--类别:维修换料
v_wareHouse
from mms_mo_mat_require mr
where mr.mat_type=5 and mr.version=v_version_code
group by mat_id,
mat_code,
mat_desc);
delete from mms_mo_mat_require where mat_type=5 and version=v_version_code;
commit; x_result:='Y';
x_msg:=to_char(v_count);
exception
when v_raise then
rollback;
x_result:='N';
x_msg:='当前日期已执行过维修换料运算。';
when others then x_result:='N';
x_msg:='程序异常';
end clc_Mat_Addition_Require3;

此时,运行效率已大大提升,测试了一下,只要0.42秒,但被导师看了之后,又提了几个问题。

1,程序中不应该使用两次commit;因为同一个会话中的数据是可以在检索到的,所以并不一定要提交到数据库才可以查看。

2,使用汇总插入并删除原来的数据也是不对的,因为针对数据库来说,删除是要写日志记录,耗费大量资源的。

所以针对此问题,又做了改动,把汇总并删除改为更新或插入。

代码如下:

  procedure clc_Mat_Addition_Require4(p_begin   date,
p_user varchar2,
x_result out varchar2,
x_msg out varchar2) is
v_count int; --处理行数
v_num number; --维修换料数
v_version_code mms_mo_ori_version.version_code%type; --版本号
v_version_id mms_mo_ori_version.version_id%type; --需求单头号
v_raise exception;
v_wareHouse mms_dictionary_item.input_code1%type; --补料仓代码
v_item_count int; --物料明细行数;
begin
v_version_code:=to_char(p_begin,'yyyyMMdd');
v_version_id := fun_mms_get_guid();
--查询字典表里的补料仓代码
select mdi.input_code1 into v_wareHouse from mms_dictionary_item mdi
where code='AdditionWarehouse';
--查询历史版本表,已执行过不允许执行
select count(*) into v_count from mms_mo_ori_version mmov
where mmov.version_code = to_char(p_begin,'yyyyMMdd'); if v_count>0 then
raise v_raise;
end if; v_count:=0;
--生成新版本头数据
insert into mms_mo_ori_version
(version_id,
version_code,
start_time,
end_time,
creation_date,
created_by,
mat_type)
values
(v_version_id,
v_version_code,
p_begin,
p_begin+1,
sysdate,
p_user,
1);--类别:维修换料 for line in (
select wdps.wip_entity_id
from mms_wdps wdps
where wdps.plan_date >= p_begin
and wdps.plan_date <= p_begin+1
)
loop
for detailLine in (
select cwr.inventory_item_id,cwr.item_code,cwr.description,sum(cwr.quantity_open) as quantity_open
from ifce.cux_wip_requirement_v cwr
where cwr.WIP_ENTITY_ID = line.wip_entity_id
and cwr.quantity_open > 0
group by cwr.INVENTORY_ITEM_ID,cwr.item_code,cwr.description
)
loop
--获取维修换料数
select ifce.wip_logistics.fun_get_Iqcquit_sum(detailLine.ITEM_CODE,trunc(p_begin))
into v_num from dual;
if (v_num >0) then --当维修换料需求比例数大于0时插入
select count(*) into v_item_count
from mms_mo_mat_require
where mat_code=detailLine.item_code and version=v_version_code; if(v_item_count>0) then
update mms_mo_mat_require set require_qty= round(require_qty+detailLine.quantity_open*v_num)
where mat_code=detailLine.item_code and version=v_version_code;
else
insert into mms_mo_mat_require
(mat_requireid,
mat_id,
mat_code,
mat_desc,
require_time,
require_qty,
status,
creation_date,
created_by,
version,
mat_type,
super_market_inv_code,
attribute4)
select fun_mms_get_guid(),
detailLine.inventory_item_id,
detailLine.item_code,
detailLine.description,
p_begin,
round(detailLine.quantity_open*v_num),
0,
sysdate,
p_user,
v_version_code,
1,
v_wareHouse,
detailLine.quantity_open||' '||v_num||' '||line.wip_entity_id
from dual;
end if;
v_count:=v_count+1;
end if;
end loop;
end loop;
commit;
x_result:='Y';
x_msg:=to_char(v_count);
exception
when v_raise then
rollback;
x_result:='N';
x_msg:='当前日期已执行过维修换料运算。';
when others then
x_result:='N';
x_msg:='程序异常';
end clc_Mat_Addition_Require4;

今天既学到了知识,又有工资拿,真是太开心啦,哈哈哈。。。

各位看官,如果有更好的建议,不吝赐教,欢迎指导。

记一次Sql优化过程的更多相关文章

  1. SQL优化过程中常见Oracle HINT

    在SQL语句优化过程中,我们经常会用到hint,现总结一下在SQL优化过程中常见Oracle HINT的用法: 1. /*+ALL_ROWS*/ 表明对语句块选择基于开销的优化方法,并获得最佳吞吐量, ...

  2. 记一次SQL优化。

    程序是数据库的用户,为打造良好的用户体验,我们一直在努力. 此次介绍一个基于SQL的数据库优化.SQL的优劣对数据库的性能影响非常关键. 查询只涉及如下表结构中的三个字段.如下 开发原始SQL SEL ...

  3. 记一次SQL优化

    常见的SQL优化 一.查询优化 1.避免全表扫描 模糊查询前后加%也属于全表扫描 在where子句中对字段进行表达式操作会导致引擎放弃使用索引而进行全表扫描,如: select id from t w ...

  4. 记一次sql优化——left join不走索引问题

    sql一执行就卡住,然后就...杀进程了 看了一下表的大小 第一反应就是加索引,然后explain看了一下走什么索引了,结果很尴尬,三个表,只走了一个索引...一群人在那纠结为毛走不了索引. 无意间发 ...

  5. 4W条人才表循环处理业务sql优化过程

    场景: 使用windows服务定时更新合同数据:执行存储过程(pas_RefreshContractStatus),但存储过程里面有一个需要更新4W条人才表循环处理业务 问题: 循环更新4W条人才表状 ...

  6. 转载:MYSQL数据库三表联查的SQL优化过程

    地址:https://database.51cto.com/art/202002/609803.htm 作者用了三张有设计缺陷的表做例子,使得优化效果空前,优化手段仅为拨乱反正和加索引,此行可为一哂.

  7. ORACLE常用SQL优化hint语句

    在SQL语句优化过程中,我们经常会用到hint,现总结一下在SQL优化过程中常见Oracle HINT的用法: 1. /*+ALL_ROWS*/ 表明对语句块选择基于开销的优化方法,并获得最佳吞吐量, ...

  8. 其实SQL优化调优,就跟吃饭喝水一样简单,教你抓住SQL的本质!

    前言 SOL 优化并不简单,做好 SOL 优化需要掌握数据库体系结构.表和索引设计.高效 SOL法.高级 SOL 语法.多种优化工具等知识,甚至还得分析业务特点,以及了解优化器的缺点.只有建立 SOL ...

  9. SQL优化原理

    SQL优化过程: 1,捕获高负荷的SQL语句-->2得到SQL语句的执行计划和统计信息--->3分析SQL语句的执行计划和统计信息--->4采取措施,对SQL语句进行调整.1找出高负 ...

随机推荐

  1. php 批量替换html标签的实例代码

    php批量替换html标签的实例代码分享.   1.把html元素全部去掉,或者保留某几个html标签 <?php $text = '<p>Test paragraph.</p ...

  2. @properties指针说明

    在iOS开发过程中,属性的定义往往与retain, assign, copy有关,我想大家都很熟悉了,在此我也不介绍,网上有很多相关文章. 现在我们看看iOS5中新的关键字strong, weak, ...

  3. IOS成长之路-调用照相机和相册功能(转)

    转载自:http://blog.csdn.net/like7xiaoben/article/details/8465237 //先设定sourceType为相机,然后判断相机是否可用(ipod)没相机 ...

  4. 类的本质、description方法、SEL、NSLog输出增强

    一.类的本质 1.类也是个对象 其实类也是一个对象,是Class类型的对象,简称“类对象” Class类型的定义 typedef struct objc_class *Class; 类名就代表着类对象 ...

  5. csu 1312 榜单(模拟题)

    http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1312 1312: 榜单 Time Limit: 1 Sec  Memory Limit: 128 ...

  6. Unity3d大会的部分总结

    原地址:http://blog.csdn.net/sgnyyy/article/details/23775219 一.项目开发,管理和发布策略 1.       四大准则 a.       美术的资源 ...

  7. C++11多线程教学(一)

    本篇教学代码可在GitHub获得:https://github.com/sol-prog/threads. 在之前的教学中,我展示了一些最新进的C++11语言内容: 1. 正则表达式(http://s ...

  8. android 多个listView的向下滚动设置 listView动态设置高度代码

    墨迹天气图: 这里都是用的android里面的shape实现的,实现起来比较简单,只是在滚动的时候有点小麻烦... 当我们多个ListView超出了它的父控件LinearLayout的时候,它们每个L ...

  9. linux ubuntu卸载软件

    1.通过deb包安装的情况: 安装.deb包: 代码:sudo dpkg -i package_file.deb反安装.deb包: 代码:sudo dpkg -r package_name 2.通过a ...

  10. 使用IDEA自带maven建java项目时报错。

    今天用IDEA建立maven项目时报错: [INFO] Scanning for projects... [INFO] Searching repository for plugin with pre ...