You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Oracle SQL执行耗时过长排查及特定条件语句功能咨询

Oracle SQL 查询性能排查与条件语句解析

嘿,作为Oracle新手碰到这种查询慢的问题确实挺闹心的,我来帮你一步步排查性能瓶颈,同时把你问的条件语句原理讲清楚:

一、查询性能缓慢的排查方向

1. 函数包裹列导致索引失效

这是你查询慢的核心原因之一:你的WHERE子句里对pinv.pipeline_tx_status_datepinv.status_date_tz_code套了自定义函数sf_get_local,还加了TRUNC。Oracle没法直接使用这两个列上的索引——它得先计算每一行的函数结果才能做过滤,这会触发全表扫描,数据量大的时候自然慢到离谱。

解决建议:

  • 优先调整逻辑,把函数移到条件右侧:比如如果sf_get_local是把存储的时区时间转成本地时间,那反过来把用户输入的&1&2转换成存储的时区时间,直接和pinv.pipeline_tx_status_date比较,避免在列上用函数。
  • 如果必须保留当前写法,可以创建基于函数的索引
    CREATE INDEX idx_pinv_local_status_date ON pipeline (TRUNC(sf_get_local(pipeline_tx_status_date, status_date_tz_code)));
    

2. 表连接缺失必要索引

检查所有JOIN关联的列是否有索引,这是连接大表时的性能关键:

  • pipeline.pipeline_tx_id(关联invoice_headerpipeline_relations
  • pipeline_relations.rel_pipeline_tx_id(关联pipeline
  • multisegment_status.pipeline_tx_id(关联pipeline
  • 另外pipeline_parties.partner_role='BT'这个过滤条件,如果partner_role的取值多且'BT'占比很小,可以给pipeline_parties(partner_role)加索引。

3. 查看执行计划定位瓶颈

执行以下语句生成执行计划,就能直观看到哪里拖慢了查询:

EXPLAIN PLAN FOR
Select pinv.pipeline_ref_id Invoice_No, pinv.orig_company_id Company, pinv.orig_terminal_id Terminal, phwb.pipeline_ref_id HWB_No, ih.transport_mode Trans_Mode, ih.import_export_ind Business_Type, to_date(ms.accounting_date,'dd/mm/yy') BL_Confirm_date, to_date(sf_get_local(pinv.pipeline_tx_status_date,pinv.status_date_tz_code),'dd/mm/yy') Inv_Void_Date, (pinv.pipeline_tx_status_date - ms.accounting_date) BL_Days, ih.billto_name BillTo_Name, ppi.partner_id BillTo_ID, pinv.last_modified_by Executed_By, ih.oc_invoice_amt Invoice_Amount From pipeline pinv JOIN invoice_header ih ON pinv.pipeline_tx_id = ih.pipeline_tx_id JOIN pipeline_relations prin ON pinv.pipeline_tx_id = prin.pipeline_tx_id JOIN pipeline phwb ON prin.rel_pipeline_tx_id = phwb.pipeline_tx_id JOIN multisegment_status ms ON phwb.pipeline_tx_id = ms.pipeline_tx_id JOIN pipeline_parties ppi ON ppi.partner_role = 'BT' Where (TRUNC(sf_get_local(pinv.pipeline_tx_status_date,pinv.status_date_tz_code)) between to_date('&1','DD-MON-YYYY:HH24:MI:SS') AND to_date('&2','DD-MON-YYYY:HH24:MI:SS'));

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

重点看Rows(预估扫描行数)和Cost(成本)列,全表扫描(TABLE ACCESS FULL)、高成本的连接步骤都是常见瓶颈。

4. 数据量与分区表检查

如果pipelinemultisegment_status是超大表,看看有没有按日期分区。如果是分区表,你的查询条件能不能触发分区裁剪(只扫描符合条件的分区),而不是扫描所有分区——这能大幅减少数据扫描量。

二、条件语句的工作原理解析

你提到的条件语句:

TRUNC(sf_get_local(pinv.pipeline_tx_status_date,pinv.status_date_tz_code)) between to_date('&1','DD-MON-YYYY:HH24:MI:SS') AND to_date('&2','DD-MON-YYYY:HH24:MI:SS')

拆解每部分的作用:

  1. sf_get_local(...):这是自定义函数,作用是把pipeline_tx_status_date中存储的时间(可能是UTC或其他时区的时间),根据status_date_tz_code指定的时区,转换为本地时间。比如存储的是UTC时间,时区码是'Asia/Shanghai',函数会返回上海时区的对应时间。
  2. TRUNC(...):Oracle的TRUNC函数对日期类型会截断时分秒,只保留日期部分。比如TRUNC(TO_DATE('01-JAN-2024 14:30:00','DD-MON-YYYY HH24:MI:SS'))会返回01-JAN-2024 00:00:00
  3. between ... AND ...:判断截断后的本地日期是否落在用户输入的两个日期范围内。注意:用户输入的&1&2是带时分秒的格式,但左边是截断后的日期(时分秒为0),所以只要截断后的日期等于&1对应的日期,或者在&1&2的日期之间,就会满足条件。比如&1是'01-JAN-2024:00:00:00',&2是'01-JAN-2024:23:59:59',那么所有本地时间在1月1日的记录都会被选中。

内容的提问来源于stack exchange,提问作者fuko

火山引擎 最新活动