Oracle SQL执行耗时过长排查及特定条件语句功能咨询
Oracle SQL 查询性能排查与条件语句解析
嘿,作为Oracle新手碰到这种查询慢的问题确实挺闹心的,我来帮你一步步排查性能瓶颈,同时把你问的条件语句原理讲清楚:
一、查询性能缓慢的排查方向
1. 函数包裹列导致索引失效
这是你查询慢的核心原因之一:你的WHERE子句里对pinv.pipeline_tx_status_date和pinv.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_header和pipeline_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. 数据量与分区表检查
如果pipeline或multisegment_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')
拆解每部分的作用:
sf_get_local(...):这是自定义函数,作用是把pipeline_tx_status_date中存储的时间(可能是UTC或其他时区的时间),根据status_date_tz_code指定的时区,转换为本地时间。比如存储的是UTC时间,时区码是'Asia/Shanghai',函数会返回上海时区的对应时间。TRUNC(...):Oracle的TRUNC函数对日期类型会截断时分秒,只保留日期部分。比如TRUNC(TO_DATE('01-JAN-2024 14:30:00','DD-MON-YYYY HH24:MI:SS'))会返回01-JAN-2024 00:00:00。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




