耗时从 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执行效率优化的主要内容,如果未能解决你的问题,请参考以下文章

Redis性能调优

如何查看SqlServer查询语句的执行效率

关于web多标签多条件筛选的思考

JVM 调优一个月,性能提升了 400 倍!

JVM 调优一个月,性能提升了 400 倍!

JVM 调优一个月,性能提升了 400 倍!