耗时从 400+m 到 30s 的SQL执行效率优化
Posted Jane Chiu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了耗时从 400+m 到 30s 的SQL执行效率优化相关的知识,希望对你有一定的参考价值。
最近在其他项目上,同事让我帮忙看一个查询很慢的视图,前提是在给我之前他们内部已进行优化了,当我看了他们的优化,其实就是简单地使用hint语句,而且并没有起到作用。
首先大概描述一下这个视图的情况,它是由三段sql union组成,总共大概220+行,里面有部分字段值是通过DBLINK获取的。详细如下:
CREATE OR REPLACE VIEW CUX_DWMS_GROUP_LOT_ITA_V AS
select t.batch_no,
t.delivery_detail_id,
t.order_type,
t.virtual_ship_flag,
t.ship_number,
t.source_header_number,
t.source_line_number,
t.reference_number,
t.party_name,
t.ship_add,
t.item_number,
t.item_name,
t.requested_quantity,
t.picked_qty,
t.requested_quantity_uom,
t.pick_person,
t.schedule_ship_date,
t.ordered_date,
t.organization_id,
t.organization_code,
t.organization_name,
t.subinventory,
t.ship_method_code,
t.ship_method,
t.released_status,
t.line_status,
t.remark,
t.creation_date,
t.printed_flag,
t.box_count,
t.pack_method,
t.ship_desctiption,
t.ddt_type
from (SELECT /*+ leading (ooh) index(ooh ONT.OE_ORDER_HEADERS_N11) index (csi CUX.CUX_SHIP_INPUT_INFO_ITA_N01)*/
row_number() over(partition by trh.request_number, wdd.source_header_number, wdd.source_line_number order by wdd.delivery_detail_id desc) rn,
trh.request_number batch_no,
wdd.delivery_detail_id,
ott.attribute2 order_type,
ooh.attribute9 virtual_ship_flag,
(select csi.print_num
from cux_ship_input_info_ita csi
where csi.batch_num = trh.request_number
and csi.source_header_number = wdd.source_header_number) ship_number,
wdd.source_header_number,
wdd.source_line_number,
wdd.reference_number,
ooh.attribute5 party_name,
ool.attribute1 || '.' || ool.attribute4 ship_add,
msib.segment1 item_number,
msib.description item_name,
wdd.requested_quantity,
nvl(trl.quantity_delivered, 0) picked_qty,
wdd.requested_quantity_uom,
ooh.attribute6 pick_person,
ool.schedule_ship_date,
ooh.ordered_date,
ood.organization_id,
ood.organization_code,
ood.organization_name,
wdd.ORIGINAL_SUBINVENTORY subinventory,
ool.attribute2 ship_method_code,
ool.attribute3 ship_method,
wdd.released_status,
flv.meaning line_status,
ooh.attribute2 remark,
ooh.creation_date,
decode(csi.print_flag, NULL, 'N', 'Y') printed_flag,
csi.box_count, --件数
csi.pack_method, --装货方式
csi.ship_desctiption, --描述
(select flv.lookup_code
from fnd_lookup_values_vl flv,
apps.cux_mid_order_header_temp_t@db_iwms.dahuatech.com cmo,
--apps.oe_order_headers_all@db_iwms.dahuatech.com ooh1,
cux_wms_so_sync_all cws
where cmo.freasonsforshipment = flv.MEANING
and flv.lookup_type = 'CUX_PRINT_TEMPLATE_MAPPING'
and cmo.fodernumber = cws.order_number
and cws.mo_number = ooh.order_number
and rownum<2
/*group by flv.lookup_code*/) ddt_type
FROM wsh_delivery_details wdd,
wsh_delivery_assignments wda,
oe_order_headers_all ooh,
mtl_txn_request_lines trl,
mtl_txn_request_headers trh,
ont.oe_transaction_types_all ott,
oe_order_lines_all ool,
mtl_system_items_b msib,
org_organization_definitions ood,
fnd_lookup_values flv,
cux_ship_input_info_ita csi
WHERE 1 = 1
AND trh.header_id = trl.header_id
AND trl.line_id = wdd.move_order_line_id
AND wda.delivery_detail_id = wdd.delivery_detail_id
AND ool.header_id = ooh.header_id
AND ooh.order_type_id = ott.transaction_type_id
AND wdd.source_line_id = ool.line_id
AND wdd.source_code = 'OE'
AND wdd.inventory_item_id = msib.inventory_item_id
AND wdd.organization_id = msib.organization_id
AND wdd.organization_id = ood.organization_id
AND flv.lookup_type = 'PICK_STATUS'
AND flv.lookup_code = wdd.released_status
AND flv.enabled_flag = 'Y'
AND (SYSDATE BETWEEN flv.start_date_active AND
nvl(flv.end_date_active, SYSDATE + 2))
AND flv.language = userenv('LANG')
AND ooh.flow_status_code in ('BOOKED', 'CLOSED')
AND ood.ORGANIZATION_CODE = '941'
AND wdd.released_status in ('Y', 'C')
AND csi.batch_num = trh.request_number
AND csi.source_header_number = wdd.source_header_number
) t
WHERE t.rn = 1
UNION
--样品领用
select /*+index (csi CUX.CUX_SHIP_INPUT_INFO_ITA_N01)*/mtrh1.request_number batch_no,
0 delivery_detail_id,
'Move Order' order_type,
'' virtual_ship_flag,
'' ship_number,
'' source_header_number,
'' source_line_number,
'' reference_number,
decode(cic.Accnt_name,
'海外内部测试',
cic.bus_owner,
cic.accnt_name) party_name,
cic.addr ship_add,
cic.part_num item_number,
msi.description item_name,
mtrl.quantity requested_quantity,
mmt.transaction_quantity picked_qty,
msi.primary_uom_code requested_quantity_uom,
(select to_char(user_name)
from fnd_user
where user_id = mmt.created_by) pick_person,
mtrh.creation_date schedule_ship_date,
mtrh.creation_date ordered_date,
mmt.organization_id organization_id,
cic.out_inv_org organization_code,
(select organization_name
from org_organization_definitions
where organization_code = cic.out_inv_org) organization_name,
mmt.subinventory_code subinventory,
'' ship_method_code,
'' ship_method,
'' released_status,
'' line_status,
'' remark,
sysdate creation_date,
csi.print_flag printed_flag,
csi.box_count box_count,
csi.pack_method pack_method,
csi.ship_desctiption ship_desctiption,
decode(cic.accnt_name, '海外内部测试', 'B9', 'B4') DDT_TYPE
from apps.cux_inv_crm_move_orders@db_iwms.dahuatech.com cic,
apps.mtl_txn_request_headers@db_iwms.dahuatech.com mtrh,
apps.mtl_txn_request_lines@db_iwms.dahuatech.com mtrl,
mtl_material_transactions mmt,
mtl_txn_request_headers mtrh1,
mtl_txn_request_lines mtrl1,
mtl_system_items_b msi,
cux_ship_input_info_ita csi
where cic.out_inv_org = '941'
and cic.process_status = 'S'
and cic.move_order_header_id = mtrh.header_id
and cic.move_order_line_id = mtrl.line_id
and msi.inventory_item_id = mmt.inventory_item_id
and msi.organization_id = mmt.organization_id
and mtrh1.header_id = mmt.transaction_source_id
and mtrl1.header_id = mtrl1.header_id
and mtrl1.line_id = mmt.trx_source_line_id
and mmt.transaction_type_id = 160
and mmt.organization_id = 270
and mmt.transaction_quantity > 0
and mtrl1.line_number = mtrl.line_number
and mtrh1.request_number = 'W' || mtrh.request_number
and mtrh1.request_number=csi.batch_num(+)
UNION
--转库,针对中部仓和米兰仓
select /*+index (csi CUX.CUX_SHIP_INPUT_INFO_ITA_N01)*/mtrh.request_number batch_no,
0 delivery_detail_id,
'Move Order' order_type,
'' virtual_ship_flag,
'' ship_number,
'' source_header_number,
'' source_line_number,
'' reference_number,
'Dahua Technology S.r.l.' party_name,
'Via Brughetti, 9/h - 20813 Bovisio Masciago (MB)' ship_add,
msi.segment1 item_number,
msi.description item_name,
mtrl.quantity requested_quantity,
sum(mmt.transaction_quantity) picked_qty,
msi.primary_uom_code requested_quantity_uom,
(select to_char(user_name)
from fnd_user
where user_id = mmt.created_by) pick_person,
mtrh.creation_date schedule_ship_date,
mtrh.creation_date ordered_date,
mmt.organization_id organization_id,
ood.organization_code organization_code,
ood.organization_name organization_name,
mmt.subinventory_code subinventory,
'' ship_method_code,
'' ship_method,
'' released_status,
'' line_status,
'' remark,
sysdate creation_date,
csi.print_flag printed_flag,
csi.box_count box_count,
csi.pack_method pack_method,
csi.ship_desctiption ship_desctiption,
'S1' DDT_TYPE
from mtl_material_transactions mmt,
mtl_txn_request_headers mtrh,
mtl_txn_request_lines mtrl,
mtl_system_items_b msi,
org_organization_definitions ood,
cux_ship_input_info_ita csi
where mtrh.header_id = mmt.transaction_source_id
and mtrl.line_id = mmt.trx_source_line_id
and mtrh.header_id = mtrh.header_id
and mmt.organization_id = mtrh.organization_id
and msi.inventory_item_id = mtrl.inventory_item_id
and msi.organization_id = mmt.organization_id
and ood.ORGANIZATION_ID = mmt.ORGANIZATION_ID
and mmt.transaction_type_id = 115 --子库存转移
and mmt.organization_id = 270
and mmt.transaction_quantity > 0
and ((mtrl.to_subinventory_code = '91.02.01' and
mtrl.from_subinventory_code = '91.02.02') or
(mtrl.to_subinventory_code = '91.02.02' and
mtrl.from_subinventory_code = '91.02.01'))
and mtrh.request_number = csi.batch_num
and not exists (select 1
from mtl_txn_request_lines mtrl1
where mtrl1.line_id = mtrl.line_id
and mtrl1.line_status = ('7')) --确保搬运单行没有打开状态
--and mtrh.request_number = 'W10194646'
group by mtrh.request_number,
msi.segment1,
msi.description,
mtrl.quantity,
msi.primary_uom_code,
mmt.created_by,
mtrh.creation_date,
mtrh.creation_date,
mmt.organization_id,
ood.organization_code,
ood.organization_name,
mmt.subinventory_code ,
csi.print_flag,
csi.box_count,
csi.pack_method,
csi.ship_desctiption;
其次,在plsql里查询了一下这个视图,200+分钟过去了没有执行出结果,终于等到跑完打出trace日志文件。这段SQL出来的结果只有6条数据,为什么耗时这么长呢?
最后,我来说说我的sql优化思路吧
- 一般Sql优化都得从根入手,进行SQL调整,大多数技术或顾问或客户在写SQL时都是只顾执行结果不顾其在时间/空间等性能,所以大多数SQL都是千疮百孔的经不起推敲,那么在进行SQL调整的前提是确保结果正确。SQL调整目的在于两点 :1、利用Oracle中的数据集驱动,让数据量小的结果集为主,关联其他表或对象;2、让where子句条件走索引,尽量走结果集小的索引。调整过后的视图如下:
CREATE OR REPLACE VIEW CUX_DWMS_GROUP_LOT_ITA_V AS
select t.batch_no,
t.delivery_detail_id,
t.order_type,
t.virtual_ship_flag,
t.ship_number,
t.source_header_number,
t.source_line_number,
t.reference_number,
t.party_name,
t.ship_add,
t.item_number,
t.item_name,
t.requested_quantity,
t.picked_qty,
t.requested_quantity_uom,
t.pick_person,
t.schedule_ship_date,
t.ordered_date,
t.organization_id,
t.organization_code,
t.organization_name,
t.subinventory,
t.ship_method_code,
t.ship_method,
t.released_status,
t.line_status,
t.remark,
t.creation_date,
t.printed_flag,
t.box_count,
t.pack_method,
t.ship_desctiption,
t.ddt_type
from (SELECT row_number() over(partition by trh.request_number, wdd.source_header_number, wdd.source_line_number order by wdd.delivery_detail_id desc) rn,
trh.request_number batch_no,
wdd.delivery_detail_id,
(select ott.attribute2
from ont.oe_transaction_types_all ott
where ooh.order_type_id = ott.transaction_type_id) order_type,
ooh.attribute9 virtual_ship_flag,
(select csi.print_num
from cux_ship_input_info_ita csi
where csi.batch_num = trh.request_number
and csi.source_header_number = wdd.source_header_number) ship_number,
wdd.source_header_number,
wdd.source_line_number,
wdd.reference_number,
ooh.attribute5 party_name,
ool.attribute1 || '.' || ool.attribute4 ship_add,
msib.segment1 item_number,
msib.description item_name,
wdd.requested_quantity,
nvl(trl.quantity_delivered, 0) picked_qty,
wdd.requested_quantity_uom,
ooh.attribute6 pick_person,
ool.schedule_ship_date,
ooh.ordered_date,
ood.organization_id,
ood.organization_code,
ood.organization_name,
wdd.original_subinventory subinventory,
ool.attribute2 ship_method_code,
ool.attribute3 ship_method,
wdd.released_status,
(select flv.meaning
from fnd_lookup_values_vl flv
where 1 = 1
AND flv.lookup_type = 'PICK_STATUS'
AND flv.lookup_code = wdd.released_status
AND flv.enabled_flag = 'Y'
AND (SYSDATE BETWEEN flv.start_date_active AND
nvl(flv.end_date_active, SYSDATE + 2))) line_status,
ooh.attribute2 remark,
ooh.creation_date,
decode(csi.print_flag, NULL, 'N', 'Y') printed_flag,
csi.box_count, --件数
csi.pack_method, --装货方式
csi.ship_desctiption, --描述
(select flv.lookup_code
from fnd_lookup_values_vl flv,
apps.cux_mid_order_header_temp_t@db_iwms.dahuatech.com cmo,
cux_wms_so_sync_all cws -- 不走T2索引
where cmo.freasonsforshipment = flv.MEANING
and flv.lookup_type = 'CUX_PRINT_TEMPLATE_MAPPING'
and cmo.fodernumber = cws.order_number
and cws.mo_number = ooh.order_number
and rownum = 1) ddt_type
FROM wsh_delivery_details wdd,
oe_order_headers_all ooh,
oe_order_lines_all ool,
mtl_txn_request_lines trl,
mtl_txn_request_headers trh,
mtl_system_items_b msib,
org_organization_definitions ood,
cux_ship_input_info_ita csi
WHERE 1 = 1
and wdd.source_header_id = ooh.header_id
AND wdd.source_line_id = ool.line_id
AND wdd.source_code = 'OE'
AND wdd.released_status in ('Y', 'C')
and wdd.inventory_item_id = ool.inventory_item_id
AND wdd.move_order_line_id = trl.line_id
and wdd.inventory_item_id = trl.inventory_item_id
and wdd.organization_id = trl.organization_id
AND wdd.inventory_item_id = msib.inventory_item_id
AND wdd.organization_id = msib.organization_id
AND wdd.organization_id = ood.organization_id
AND trh.header_id = trl.header_id
AND ooh.header_id = ool.header_id
AND ooh.flow_status_code in ('BOOKED', 'CLOSED')
AND ood.organization_id = 270
AND csi.batch_num = trh.request_number
AND csi.source_header_number = wdd.source_header_number) t
WHERE t.rn = 1
UNION
--样品领用
select wms_temp.request_number batch_no,
0 delivery_detail_id,
'Move Order' order_type,
'' virtual_ship_flag,
'' ship_number,
'' source_header_number,
'' source_line_number,
'' reference_number,
decode(ebs_temp.accnt_name,
'海外内部测试',
ebs_temp.bus_owner,
ebs_temp.accnt_name) party_name,
ebs_temp.addr ship_add,
ebs_temp.part_num item_number,
wms_temp.description item_name,
ebs_temp.quantity requested_quantity,
wms_temp.transaction_quantity picked_qty,
wms_temp.primary_uom_code requested_quantity_uom,
(select to_char(user_name)
from fnd_user
where user_id = wms_temp.created_by) pick_person,
ebs_temp.creation_date schedule_ship_date,
ebs_temp.creation_date ordered_date,
wms_temp.organization_id organization_id,
ebs_temp.out_inv_org organization_code,
(select organization_name
from org_organization_definitions
where organization_code = ebs_temp.out_inv_org) organization_name,
wms_temp.subinventory_code subinventory,
'' ship_method_code,
'' ship_method,
'' released_status,
'' line_status,
'' remark,
sysdate creation_date,
csi.print_flag printed_flag,
csi.box_count box_count,
csi.pack_method pack_method,
csi.ship_desctiption ship_desctiption,
decode(ebs_temp.accnt_name, '海外内部测试', 'B9', 'B4') ddt_type
from (select cic.addr,
cic.part_num,
mtrl.quantity,
mtrh.creation_date,
mtrh.request_number,
mtrl.line_number,
cic.out_inv_org,
cic.bus_owner,
cic.accnt_name
from apps.cux_inv_crm_move_orders@db_iwms.dahuatech.com cic,
apps.mtl_txn_request_headers@db_iwms.dahuatech.com mtrh,
apps.mtl_txn_request_lines@db_iwms.dahuatech.com mtrl
where cic.out_inv_org = '941'
and cic.process_status = 'S'
and cic.move_order_header_id = mtrh.header_id
and cic.move_order_line_id = mtrl.line_id
and mtrh.header_id = mtrl.line_id) ebs_temp,
(select mtrh1.request_number,
mtrl1.line_number,
msi.description,
mmt.transaction_quantity,
msi.primary_uom_code,
mmt.created_by,
mmt.organization_id,
mmt.subinventory_code
from mtl_material_transactions mmt,
mtl_txn_request_headers mtrh1,
mtl_txn_request_lines mtrl1,
mtl_system_items_b msi
where 1 = 1
and msi.inventory_item_id = mmt.inventory_item_id
and msi.organization_id = mmt.organization_id
and mtrh1.header_id = mmt.transaction_source_id
and mtrl1.header_id = mtrl1.header_id
and mtrl1.line_id = mmt.trx_source_line_id
and mmt.transaction_type_id = 160
and mmt.organization_id = 270
and mmt.transaction_quantity > 0) wms_temp,
cux_ship_input_info_ita csi
where 1 = 1
and wms_temp.line_number = ebs_temp.line_number
and wms_temp.request_number = 'W' || ebs_temp.request_number
and wms_temp.request_number = csi.batch_num(+)
UNION
--转库,针对中部仓和米兰仓
select mmt_temp.batch_no,
0 delivery_detail_id,
'Move Order' order_type,
'' virtual_ship_flag,
'' ship_number,
'' source_header_number,
'' source_line_number,
'' reference_number,
'Dahua Technology S.r.l.' party_name,
'Via Brughetti, 9/h - 20813 Bovisio Masciago (MB)' ship_add,
mmt_temp.item_number,
mmt_temp.item_name,
mmt_temp.requested_quantity,
mmt_temp.picked_qty,
mmt_temp.requested_quantity_uom,
(select to_char(user_name)
from fnd_user
where user_id = mmt_temp.created_by) pick_person,
mmt_temp.creation_date schedule_ship_date,
mmt_temp.creation_date ordered_date,
mmt_temp.organization_id,
ood.organization_code organization_code,
ood.organization_name organization_name,
mmt_temp.subinventory,
'' ship_method_code,
'' ship_method,
'' released_status,
'' line_status,
'' remark,
sysdate creation_date,
csi.print_flag printed_flag,
csi.box_count box_count,
csi.pack_method pack_method,
csi.ship_desctiption ship_desctiption,
'S1' ddt_type
from (select mtrh.request_number batch_no,
msi.segment1 item_number,
msi.description item_name,
mtrl.quantity requested_quantity,
sum(mmt.transaction_quantity) picked_qty,
msi.primary_uom_code requested_quantity_uom,
mmt.created_by,
mtrh.creation_date,
mmt.organization_id,
mmt.subinventory_code subinventory
from mtl_material_transactions mmt,
mtl_txn_request_headers mtrh,
inv.mtl_txn_request_lines mtrl,
mtl_system_items_b msi
where 1 = 1
and mmt.transaction_source_id = mtrh.header_id
and mmt.trx_source_line_id = mtrl.line_id
and mmt.organization_id = mtrl.organization_id
and mmt.inventory_item_id = msi.inventory_item_id
and mmt.organization_id = msi.organization_id
and mtrh.header_id = mtrl.header_id
and mmt.transaction_type_id = 115 --子库存转移
and mmt.transaction_quantity > 0
and mmt.organization_id = 270
and ((mtrl.to_subinventory_code = '91.02.01' and
mtrl.from_subinventory_code = '91.02.02') or
(mtrl.to_subinventory_code = '91.02.02' and
mtrl.from_subinventory_code = '91.02.01'))
and mtrl.line_status <> '7' --确保搬运单行没有打开状态
group by mtrh.request_number,
msi.segment1,
msi.description,
mtrl.quantity,
msi.primary_uom_code,
mmt.created_by,
mtrh.creation_date,
mmt.organization_id,
mmt.subinventory_code) mmt_temp,
org_organization_definitions ood,
cux_ship_input_info_ita csi
where 1 = 1
and mmt_temp.batch_no = csi.batch_num
and mmt_temp.organization_id = ood.organization_id;
调整过后,cost 从 383.4w 降到了 1.8w。
- sql调整后再次查询视图,其执行时间并不理想,故而得通过trace文件去分析了。
这里是select结果上的子查询,其表的T2索引是建在order_number字段上的,而且此处还有dblink。首先强烈建议客户调整一下此处取值sql,最不济的办法是用hint指定索引。
这处也需要调整,但看了其sql和表上索引字段【move_order_line_id】,也并无不妥,如果一定要调整,只有调整索引,建在move_order_line_id 和released_status上缩小结果集,但个人不是很建议,很多人认为SQL优化就是走索引,就是用走索引来取代全表扫描,实际上这种认识是非常肤浅的。首先,在Oracle数据库里,不是说走索引就一定比全表扫描号,例如在很多情况下走索引的嵌套循坏连接的执行效率往往比不上走全表扫描的哈希连接的执行效率;其次,SQL优化通常都是调整执行计划来达到优化目的的,用走索引来取代全表扫描只是地执行计划调整中的一种;最后,即便是走索引,也会有一些额外的变化,如果对CBO和执行计划理解得不深刻,不了解这些变化,即便建了索引,也可能会没有效果。
如上调整后,执行时间控制在了20-50秒内。
以上是关于耗时从 400+m 到 30s 的SQL执行效率优化的主要内容,如果未能解决你的问题,请参考以下文章