You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle中子查询性能远慢于SQL Server的原因排查求助

Oracle vs SQL Server视图查询性能差异分析

我定义了如下Oracle视图,查询耗时24秒,但相同逻辑在SQL Server中仅需8秒。现提供视图定义及Oracle执行计划,请求分析性能差异原因。

视图定义

create or replace view XWDDSB143.v_getBillSummaryByService
as
    SELECT
        b.BILL_NO BILLINFO_BILLNO, b.ACCOUNT_NO ACCTINFO_ACCOUNTNO, d.device_id as msisdn, d.name, d.serviceTag,
        ( SELECT NVL( Sum( amount ), 0 ) FROM XWDDSB143.v_getplans p WHERE p.device_id = d.device_id ) as plans,
        ( SELECT NVL( Sum( amount ), 0 ) FROM XWDDSB143.v_getOneTime o WHERE o.device_id = d.device_id ) as onetimes,
        ( SELECT NVL( Sum( amount ), 0 ) FROM XWDDSB143.v_getDiscounts dc WHERE dc.device_id = d.device_id ) as discounts,
        ( SELECT NVL( Sum( amount ), 0 ) FROM XWDDSB143.v_getUsage_detailed_report u WHERE u.device_id = d.device_id ) as usage,
        CASE WHEN d.serviceTag IN ( 'mobileline', 'fixedline', 'sipt' ) THEN
            ( SELECT NVL( Sum( amount ), 0 ) FROM XWDDSB143.v_getExtras e WHERE e.device_id = d.device_id )
            ELSE 0 END
            AS extras,
        CASE WHEN d.serviceTag IN ( 'mobileline', 'fixedline', 'sipt' ) THEN
            ( SELECT NVL( Sum( amount ), 0 ) FROM XWDDSB143.v_getUsage_detailed_report u WHERE u.device_id = d.device_id and u.usageCategory = 'local' and u.usageType = 'voice' )
            ELSE 0 END AS usage_calls_local,
        
        0 as tax_amount,0 as total
    FROM XWDDSB143.v_getDevices_detailed_report d
    inner join XWDDSB143.v_getBill b  on 1=1;

Oracle执行计划

Plan hash value: 3897901392
 
    1352    SELECT STATEMENT  
1    SORT AGGREGATE 
4     VIEW  V_GETPLANS
       UNION-ALL  
3       NESTED LOOPS  
3        NESTED LOOPS OUTER 
3         NESTED LOOPS OUTER 
3          NESTED LOOPS  
3           NESTED LOOPS  
3            TABLE ACCESS FULL AR_ITEMS
1            TABLE ACCESS BY INDEX ROWID BATCHED AR_ITEMS_EVENTS
1             INDEX RANGE SCAN IX_AR_ITEMS_EVENTS_13140_13139
1           TABLE ACCESS BY INDEX ROWID BATCHED AR_ITEMS_EVENTS_TOTAL
1            INDEX RANGE SCAN IDX_ARITEMSEVENTSID_TOTAL
1          INDEX RANGE SCAN IDX_ARITEMSEVENTSID_TAXES
1         TABLE ACCESS BY INDEX ROWID BATCHED AR_ITEMS_EVENTS_PRODUCTS
1          INDEX RANGE SCAN IDX_ARITEMSEVENTSID_PRODUCTS
1        INDEX RANGE SCAN IDX_ARITEMSEVENTSID_CYCLE_INFO
1       HASH JOIN  
1        NESTED LOOPS  
1         NESTED LOOPS OUTER 
1          NESTED LOOPS  
1           NESTED LOOPS OUTER 
1            TABLE ACCESS FULL SUB_ITEMS_EVENTS
1            INDEX RANGE SCAN IDX_SUBITEMSEVENTSID_TAXES
1           TABLE ACCESS BY INDEX ROWID BATCHED SUB_ITEMS_EVENTS_TOTAL
1            INDEX RANGE SCAN IDX_SUBITEMSEVENTSID_TOTAL
1          TABLE ACCESS BY INDEX ROWID BATCHED SUB_ITEMS_EVENTS_PRODUCTS
1           INDEX RANGE SCAN IDX_SUBITEMSEVENTSID_PRODUCTS
1         INDEX RANGE SCAN IDX_SUBITEMSEVENTSID_CYCLE_INFO
1        TABLE ACCESS FULL SUB_ITEMS
1    SORT AGGREGATE 
2     VIEW  V_GETONETIME
       UNION-ALL  
1       NESTED LOOPS  
1        NESTED LOOPS  
1         NESTED LOOPS  
1          NESTED LOOPS  
1           NESTED LOOPS OUTER 
1            TABLE ACCESS BY INDEX ROWID BATCHED AR_ITEMS_EVENTS
              BITMAP CONVERSION TO ROWIDS 
               BITMAP OR  
                BITMAP CONVERSION FROM ROWIDS 
                 SORT ORDER BY 
                  INDEX RANGE SCAN IX_AR_ITEMS_EVENTS_23188_23187
                BITMAP CONVERSION FROM ROWIDS 
                 SORT ORDER BY 
                  INDEX RANGE SCAN IX_AR_ITEMS_EVENTS_23188_23187
                BITMAP CONVERSION FROM ROWIDS 
                 SORT ORDER BY 
                  INDEX RANGE SCAN IX_AR_ITEMS_EVENTS_23188_23187
1            INDEX RANGE SCAN IDX_ARITEMSEVENTSID_TAXES
1           TABLE ACCESS BY INDEX ROWID BATCHED AR_ITEMS
1            INDEX RANGE SCAN IDX_ARITEMSID
1          TABLE ACCESS BY INDEX ROWID BATCHED AR_ITEMS_EVENTS_PRODUCTS
1           INDEX RANGE SCAN IDX_ARITEMSEVENTSID_PRODUCTS
1         INDEX RANGE SCAN IDX_ARITEMSEVENTSID_TOTAL
1        TABLE ACCESS BY INDEX ROWID AR_ITEMS_EVENTS_TOTAL
1       NESTED LOOPS OUTER 
1        NESTED LOOPS  
1         NESTED LOOPS  
1          HASH JOIN  
1           TABLE ACCESS FULL SUB_ITEMS
1           TABLE ACCESS FULL SUB_ITEMS_EVENTS
1          TABLE ACCESS BY INDEX ROWID BATCHED SUB_ITEMS_EVENTS_PRODUCTS
1           INDEX RANGE SCAN IDX_SUBITEMSEVENTSID_PRODUCTS
1         TABLE ACCESS BY INDEX ROWID BATCHED SUB_ITEMS_EVENTS_TOTAL
1          INDEX RANGE SCAN IDX_SUBITEMSEVENTSID_TOTAL
1        INDEX RANGE SCAN IDX_SUBITEMSEVENTSID_TAXES
1    SORT AGGREGATE 
2     VIEW  V_GETDISCOUNTS
       UNION-ALL  
        FILTER  
1        SORT GROUP BY 
3         NESTED LOOPS OUTER 
3          HASH JOIN  
15          NESTED LOOPS  
477          NESTED LOOPS  
3             TABLE ACCESS FULL AR_ITEMS
159           INDEX RANGE SCAN IX_AR_ITEMS_EVENTS_13140_13139
5            TABLE ACCESS BY INDEX ROWID AR_ITEMS_EVENTS
1919            TABLE ACCESS FULL AR_ITEMS_EVENTS_DISCOUNTS
1          TABLE ACCESS BY INDEX ROWID BATCHED AR_ITEMS_EVENTS_CYCLE_INFO
1           INDEX RANGE SCAN IDX_ARITEMSEVENTSID_CYCLE_INFO
        FILTER  
1        SORT GROUP BY 
1         NESTED LOOPS  
1          NESTED LOOPS  
1           NESTED LOOPS OUTER 
1            HASH JOIN  
1             TABLE ACCESS FULL SUB_ITEMS
1             TABLE ACCESS FULL SUB_ITEMS_EVENTS
1            TABLE ACCESS BY INDEX ROWID BATCHED SUB_ITEMS_EVENTS_CYCLE_INFO
1             INDEX RANGE SCAN IDX_SUBITEMSEVENTSID_CYCLE_INFO
1           INDEX RANGE SCAN IDX_SUBITEMSEVENTSID_DISCOUNTS
1          TABLE ACCESS BY INDEX ROWID SUB_ITEMS_EVENTS_DISCOUNTS
1    SORT AGGREGATE 
6     VIEW  V_GETUSAGE_DETAILED_REPORT
6      SORT GROUP BY 
481     TABLE ACCESS FULL USAGEDATA
1    SORT AGGREGATE 
2     VIEW  V_GETEXTRAS
       UNION-ALL  
1       NESTED LOOPS OUTER 
1        NESTED LOOPS OUTER 
1         NESTED LOOPS  
1          NESTED LOOPS OUTER 
1           NESTED LOOPS  
3            TABLE ACCESS FULL AR_ITEMS
1            TABLE ACCESS BY INDEX ROWID BATCHED AR_ITEMS_EVENTS
1             INDEX RANGE SCAN IX_AR_ITEMS_EVENTS_13140_13139
1           INDEX RANGE SCAN IDX_ARITEMSEVENTSID_TAXES
1          TABLE ACCESS BY INDEX ROWID BATCHED AR_ITEMS_EVENTS_TOTAL
1           INDEX RANGE SCAN IDX_ARITEMSEVENTSID_TOTAL
1         INDEX RANGE SCAN IDX_ARITEMSEVENTSID_CYCLE_INFO
1        TABLE ACCESS BY INDEX ROWID BATCHED AR_ITEMS_EVENTS_PRODUCTS
1         INDEX RANGE SCAN IDX_ARITEMSEVENTSID_PRODUCTS
1       HASH JOIN  
1        NESTED LOOPS OUTER 
1         NESTED LOOPS  
1          NESTED LOOPS OUTER 
1           NESTED LOOPS OUTER 
1            TABLE ACCESS FULL SUB_ITEMS_EVENTS
1            INDEX RANGE SCAN IDX_SUBITEMSEVENTSID_TAXES
1           INDEX RANGE SCAN IDX_SUBITEMSEVENTSID_CYCLE_INFO
1          TABLE ACCESS BY INDEX ROWID BATCHED SUB_ITEMS_EVENTS_TOTAL
1           INDEX RANGE SCAN IDX_SUBITEMSEVENTSID_TOTAL
1         TABLE ACCESS BY INDEX ROWID BATCHED SUB_ITEMS_EVENTS_PRODUCTS
1          INDEX RANGE SCAN IDX_SUBITEMSEVENTSID_PRODUCTS
1        TABLE ACCESS FULL SUB_ITEMS
1    SORT AGGREGATE 
1     VIEW  V_GETUSAGE_DETAILED_REPORT
1      SORT GROUP BY 
335     TABLE ACCESS FULL USAGEDATA
1    SORT AGGREGATE 
1     VIEW  V_GETUSAGE_DETAILED_REPORT
1      SORT GROUP BY 
8       TABLE ACCESS FULL USAGEDATA
1    SORT AGGREGATE 
1     VIEW  V_GETUSAGE_DETAILED_REPORT
1      SORT GROUP BY 
1       TABLE ACCESS FULL USAGEDATA
1    SORT AGGREGATE 
2     VIEW  V_GETUSAGE_DETAILED_REPORT
2      SORT GROUP BY 
8       TABLE ACCESS FULL USAGEDATA
1    SORT AGGREGATE 
1     VIEW  V_GETUSAGE_DETAILED_REPORT
1      SORT GROUP BY 
94      TABLE ACCESS FULL USAGEDATA
1    SORT AGGREGATE 
1     VIEW  V_GETUSAGE_DETAILED_REPORT
1      SORT GROUP BY 
1       TABLE ACCESS FULL USAGEDATA
1    SORT AGGREGATE 
1     VIEW  V_GETUSAGE_DETAILED_REPORT
1      SORT GROUP BY 
1       TABLE ACCESS FULL USAGEDATA
1    SORT AGGREGATE 
1     VIEW  V_GETVAS
1      SORT GROUP BY 
1       NESTED LOOPS  
1        NESTED LOOPS  
1         NESTED LOOPS  
1          NESTED LOOPS OUTER 
1           NESTED LOOPS  
             INLIST ITERATOR  
1             TABLE ACCESS BY INDEX ROWID BATCHED AR_ITEMS_EVENTS_CRBT_INFO
1              INDEX RANGE SCAN IDX_AR_ITEMS_EVENTS_CRBT_INFO_EVENTYPE
1            INDEX RANGE SCAN IX_AR_ITEMS_EVENTS_699075_699074
1           TABLE ACCESS BY INDEX ROWID BATCHED AR_ITEMS_EVENTS_TAXES
1            INDEX RANGE SCAN IDX_ARITEMSEVENTSID_TAXES
1          TABLE ACCESS BY INDEX ROWID BATCHED AR_ITEMS
1           INDEX RANGE SCAN IDX_ARITEMSID
1         INDEX RANGE SCAN IDX_ARITEMSEVENTSID_TOTAL
1        TABLE ACCESS BY INDEX ROWID AR_ITEMS_EVENTS_TOTAL
     FILTER  
1412      NESTED LOOPS  
26     MERGE JOIN CARTESIAN 
1       MERGE JOIN CARTESIAN 
1        MERGE JOIN CARTESIAN 
1         MERGE JOIN CARTESIAN 
1          VIEW  
1           WINDOW NOSORT STOPKEY 
1            TABLE ACCESS FULL NAMEINFO
1          BUFFER SORT 
1           INDEX FULL SCAN INV_INFO_PK
1         BUFFER SORT 
1          TABLE ACCESS FULL ACCTINFO
1        BUFFER SORT 
1         TABLE ACCESS FULL BILLINFO
26      BUFFER SORT 
26       TABLE ACCESS FULL SERVICETYPE
54     VIEW  V_GETDEVICES
692     SORT UNIQUE 
692      TABLE ACCESS FULL DEVICES
1     TABLE ACCESS FULL SERVICETYPE

性能差异原因分析

1. 笛卡尔积导致的数据爆炸

视图中inner join XWDDSB143.v_getBill b on 1=1是无关联条件的笛卡尔积,这会让v_getDevices_detailed_report的每一行都和v_getBill的所有行匹配,数据量直接相乘。从执行计划能看到多次MERGE JOIN CARTESIAN操作,这会让后续所有关联子查询的执行次数呈几何级增长。SQL Server对这种场景的优化策略更高效,可能自动规避了无意义的笛卡尔积重复计算。

2. 关联子查询的重复执行

视图包含6个关联子查询(含CASE中的2个),每个子查询都会针对笛卡尔积后的每一行单独执行。比如plans字段的子查询,若笛卡尔积后有1000行,这个子查询就要跑1000次。执行计划中多次出现SORT AGGREGATE和底层视图的重复调用,比如V_GETUSAGE_DETAILED_REPORT被反复执行全表扫描和聚合,这是性能瓶颈的核心原因。SQL Server会将这类关联子查询转换为JOIN聚合,一次性计算所有device_id的结果,避免重复执行。

3. 全表扫描的重复开销

执行计划里多次出现TABLE ACCESS FULL USAGEDATA,每次都要做SORT GROUP BY,说明同一个表被反复扫描聚合,没有复用计算结果。比如usage和usage_calls_local都依赖v_getUsage_detailed_report,但Oracle没有合并这两个逻辑,而是分开执行两次全表扫描,浪费大量IO和CPU资源。

4. 视图嵌套的优化限制

所有子查询都基于嵌套视图,Oracle优化器难以穿透多层视图解析完整逻辑,无法生成最优执行计划。比如v_getplans本身是UNION ALL视图,内部还有多层嵌套循环,每次执行都要重新解析整个视图逻辑,叠加后开销巨大。

优化建议

  • 替换无意义的笛卡尔积:确认业务逻辑,用实际关联条件(比如账户ID、账单ID)替换on 1=1,避免数据膨胀。
  • 将关联子查询改为JOIN聚合:把所有子查询转换为预聚合的LEFT JOIN,一次性计算所有device_id的聚合值,示例如下:
    SELECT
        b.BILL_NO BILLINFO_BILLNO, b.ACCOUNT_NO ACCTINFO_ACCOUNTNO, d.device_id as msisdn, d.name, d.serviceTag,
        NVL(p.plans,0) plans,
        NVL(o.onetimes,0) onetimes,
        NVL(dc.discounts,0) discounts,
        NVL(u.usage,0) usage,
        CASE WHEN d.serviceTag IN ('mobileline','fixedline','sipt') THEN NVL(e.extras,0) ELSE 0 END extras,
        CASE WHEN d.serviceTag IN ('mobileline','fixedline','sipt') THEN NVL(u_local.usage_calls_local,0) ELSE 0 END usage_calls_local,
        0 as tax_amount,0 as total
    FROM XWDDSB143.v_getDevices_detailed_report d
    -- 替换笛卡尔积为合理关联
    JOIN XWDDSB143.v_getBill b ON d.account_no = b.account_no
    LEFT JOIN (SELECT device_id, SUM(amount) plans FROM XWDDSB143.v_getplans GROUP BY device_id) p ON p.device_id = d.device_id
    LEFT JOIN (SELECT device_id, SUM(amount) onetimes FROM XWDDSB143.v_getOneTime GROUP BY device_id) o ON o.device_id = d.device_id
    LEFT JOIN (SELECT device_id, SUM(amount) discounts FROM XWDDSB143.v_getDiscounts GROUP BY device_id) dc ON dc.device_id = d.device_id
    LEFT JOIN (SELECT device_id, SUM(amount) usage FROM XWDDSB143.v_getUsage_detailed_report GROUP BY device_id) u ON u.device_id = d.device_id
    LEFT JOIN (SELECT device_id, SUM(amount) extras FROM XWDDSB143.v_getExtras GROUP BY device_id) e ON e.device_id = d.device_id
    LEFT JOIN (SELECT device_id, SUM
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 14:01:11