记一次Sql优化过程
这几天在写一个存储过程,反复优化了几次,从最开始的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优化过程的更多相关文章
- SQL优化过程中常见Oracle HINT
在SQL语句优化过程中,我们经常会用到hint,现总结一下在SQL优化过程中常见Oracle HINT的用法: 1. /*+ALL_ROWS*/ 表明对语句块选择基于开销的优化方法,并获得最佳吞吐量, ...
- 记一次SQL优化。
程序是数据库的用户,为打造良好的用户体验,我们一直在努力. 此次介绍一个基于SQL的数据库优化.SQL的优劣对数据库的性能影响非常关键. 查询只涉及如下表结构中的三个字段.如下 开发原始SQL SEL ...
- 记一次SQL优化
常见的SQL优化 一.查询优化 1.避免全表扫描 模糊查询前后加%也属于全表扫描 在where子句中对字段进行表达式操作会导致引擎放弃使用索引而进行全表扫描,如: select id from t w ...
- 记一次sql优化——left join不走索引问题
sql一执行就卡住,然后就...杀进程了 看了一下表的大小 第一反应就是加索引,然后explain看了一下走什么索引了,结果很尴尬,三个表,只走了一个索引...一群人在那纠结为毛走不了索引. 无意间发 ...
- 4W条人才表循环处理业务sql优化过程
场景: 使用windows服务定时更新合同数据:执行存储过程(pas_RefreshContractStatus),但存储过程里面有一个需要更新4W条人才表循环处理业务 问题: 循环更新4W条人才表状 ...
- 转载:MYSQL数据库三表联查的SQL优化过程
地址:https://database.51cto.com/art/202002/609803.htm 作者用了三张有设计缺陷的表做例子,使得优化效果空前,优化手段仅为拨乱反正和加索引,此行可为一哂.
- ORACLE常用SQL优化hint语句
在SQL语句优化过程中,我们经常会用到hint,现总结一下在SQL优化过程中常见Oracle HINT的用法: 1. /*+ALL_ROWS*/ 表明对语句块选择基于开销的优化方法,并获得最佳吞吐量, ...
- 其实SQL优化调优,就跟吃饭喝水一样简单,教你抓住SQL的本质!
前言 SOL 优化并不简单,做好 SOL 优化需要掌握数据库体系结构.表和索引设计.高效 SOL法.高级 SOL 语法.多种优化工具等知识,甚至还得分析业务特点,以及了解优化器的缺点.只有建立 SOL ...
- SQL优化原理
SQL优化过程: 1,捕获高负荷的SQL语句-->2得到SQL语句的执行计划和统计信息--->3分析SQL语句的执行计划和统计信息--->4采取措施,对SQL语句进行调整.1找出高负 ...
随机推荐
- 用AJAX自定义日历
需求分析 在一些购物网站中,都会有促销活动,这些活动都在日历上标注出来,如何通过Ajax让日历 通过读取数据库中的信息,正确的把促销活动标注在日历上,本文通过自定义日历来实现这 个问题. 技术难点 日 ...
- linux命令 chattr超级权限控件
linux命令:chattr 1.作用 修改ext2和ext3文件系统属性(attribute),使用权限超级用户. linux命令:chattr 1.作用修改ext2和ext3文件系统属性(at ...
- install window7
install window7 http://www.zhujixc.com/win7home/http://jingyan.baidu.com/album/5bbb5a1b3e301713eba17 ...
- VB语言基础
一.常用的关键字 Dim Private Sub Public End If Else Form Me Single As Integer Unload Do While MessageBox等 二 ...
- POJ 3701 概率DP
给定2^n 支足球队进行比赛,n<=7. 队伍两两之间有一个获胜的概率,求每一个队伍赢得最后比赛的概率是多少? 状态其实都是很显然的,一开始觉得这个问题很难啊,不会.dp[i][j] 表示第i支 ...
- jsf2.0视频
jsf2.0 入门视频 教程 需要的看下.初次录视频.还有很多需要完善. JSF交流QQ群84376982 JSF入门视频下载地址 http://pan.baidu.com/s/1jG3y4T4 ...
- pageControl指示器和图片放大-b
小编由于篇幅问题,截取了最后一篇,如果需要看其他的三篇文章,可以去笔者的简书看:http://www.jianshu.com/users/9f3739421d15/latest_articles 另外 ...
- 实现WebApp直接调起NativeApp
原文http://www.baidufe.com/item/3444ee051f8edb361d12.html 试了一个小Demo,从WebApp上直接调起Android Native App,包括应 ...
- JSP页面用EL表达式 输出date格式
JSP页面用EL表达式 输出date格式 1.头上引入标签 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix ...
- XoftSpy 4.13的注册算法分析
[标题]XoftSpy 4.13的注册算法分析 [作者]forever[RCT] [语言]VC [工具]ida4.6,ollydbg1.1 [正文] 这个软件的算法很简单,正好拿来做逆向分 ...