暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

SQL优化案例| Oracle开窗函数优化案例

安呀智数据坊 2025-06-16
60

注: 本文为安丫科技焱焱枫的原创,请尊重知识产权,转发请注明出处,不接受任何抄袭、演绎和未经注明出处的转载。

在 Oracle 数据库优化领域,标量子查询(Scalar Subquery)因其语法简洁性常被用于关联查询,但在大数据量场景下却可能成为性能杀手。

这类查询的核心问题在于相关子查询的逐行执行机制—— 当主表有 N 行数据时,子查询可能被触发 N 次,导致逻辑读和 CPU 消耗呈线性增长。

更棘手的是,某些场景下即使创建索引也无法优化性能,必须通过 SQL 结构重构实现突破。

本文将结合模拟DBA_OBJECTS表的实战案例,解析标量子查询的优化困局与破解之道。

01

 适用环境 

  • oracle 11g及以上版本

  • linux 6.9及以上版本

02

 SQL概况 

今天有个客户咨询一个SQL有没有优化空间,看了眼是一个利用开窗函数来进行数据去重的SQL。

但这个SQL耗时太长,跑了10多分钟没出结果。


03

  SQL分析 

1.  SQL文本

以下SQL已经过脱敏处理

    SELECT 
      a.e_001,
      SUBSTR(a.e_002, 1, INSTR(a.e_002, '#'- 1AS p_001,
      SUBSTR(a.e_002, INSTR(a.e_002, '#'+ 12AS p_002,
      a.n_001,
      a.n_002,
      a.c_001,
      a.c_002,
      a.c_003,
      a.c_004,
      a.d_001,
      c.n_003,
      c.n_004,
      c.n_005,
      c.c_005,
      CASE
        WHEN b.n_006 = 4 THEN 1
        ELSE 2
      END AS s_001
    FROM sch_001.tbl_002 c
    INNER JOIN (
      SELECT 
        e_003,
        e_004,
        e_005,
        n_001,
        n_002,
        c_001,
        c_002,
        c_006,
        d_001,
        ROW_NUMBER() OVER (
          PARTITION BY e_003, e_004, e_005, c_001, c_002 
          ORDER BY id
        ) AS rn
      FROM sch_001.tbl_001
    ) a 
      ON a.e_004 = c.e_004
      AND a.e_003 = c.e_003
      AND a.c_001 = c.c_001
      AND a.c_002 = c.c_002
    INNER JOIN sch_001.tbl_003 b
      ON a.e_004 = b.e_004
      AND a.e_003 = b.e_003
      AND b.c_001 IS NOT NULL
      AND a.c_001 = b.c_001
      AND a.c_002 = b.c_002
    WHERE a.rn = 1
      AND b.n_007 = 4
      AND c.e_005 IS NOT NULL
      AND c.c_005 IS NOT NULL
      AND a.d_001 >= TRUNC(SYSDATE) - 1
      AND a.d_001 < TRUNC(SYSDATE);


    2. SQL执行计

      Execution Plan
      ----------------------------------------------------------
      Plan hash value8765432109
      ---------------------------------------------------------------------------------------------------------------------------------
      | Id  | Operation                  | Name            | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |
      ---------------------------------------------------------------------------------------------------------------------------------
      |   0 | SELECT STATEMENT           |                 |  2535K|  1020M|       |    14M  (1)| 47:08:43 |       |       |
      |*  1 |  HASH JOIN                 |                 |  2535K|  1020M|   992M|    14M  (1)| 47:08:43 |       |       |
      |*  2 |   HASH JOIN                |                 |  2641K|   962M|   136M|  7270K  (1)| 24:14:09 |       |       |
      |*  3 |    TABLE ACCESS FULL       | TBL_002         |  1770K|   116M|       |  7603   (2)| 00:01:32 |       |       |
      |*  4 |    VIEW                    |                 |   192M|    56G|       |  4297K  (1)| 14:19:26 |       |       |
      |*  5 |     WINDOW SORT PUSHED RANK|                 |   192M|    13G|    18G|  4297K  (1)| 14:19:26 |       |       |
      |*  6 |      FILTER                |                 |       |       |       |            |          |       |       |
      |   7 |       TABLE ACCESS FULL    | TBL_001         |   192M|    13G|       |   932K  (2)| 03:06:32 |       |       |
      |   8 |   PARTITION RANGE ALL      |                 |   123M|  4718M|       |  6517K  (1)| 21:43:27 |     1 |1048575|
      |*  9 |    TABLE ACCESS FULL       | TBL_003         |   123M|  4718M|       |  6517K  (1)| 21:43:27 |     1 |1048575|
      ---------------------------------------------------------------------------------------------------------------------------------
      Predicate Information (identified by operation id):
      ---------------------------------------------------
         1 - access("A"."E_004"="B"."E_004" AND SYS_OP_DESCEND("A"."E_004")=SYS_OP_DESCEND("B"."E_004") AND
                    "A"."E_003"="B"."E_003" AND SYS_OP_DESCEND("A"."E_003")=SYS_OP_DESCEND("B"."E_003") AND "A"."C_001"="B"."C_001" AND
                    "A"."C_002"="B"."C_002")
         2 - access("A"."E_004"="C"."E_004" AND "A"."E_003"="C"."E_003" AND "A"."C_001"="C"."C_001" AND "A"."C_002"="C"."C_002")
         3 - filter("C"."C_005" IS NOT NULL AND "C"."E_005" IS NOT NULL)
         4 - filter("A"."RN"=1 AND "A"."D_001">=TRUNC(SYSDATE)-1 AND "A"."D_001"<TRUNC(SYSDATE))
         5 - filter(ROW_NUMBER() OVER (PARTITION BY "E_003","E_004","E_005","C_001","C_002" ORDER BY "ID")<=1)
         6 - filter(TRUNC(SYSDATE)>TRUNC(SYSDATE)-1)
         9 - filter("B"."C_001" IS NOT NULL AND TO_NUMBER("B"."N_007")=4)


      3. SQL资源消耗

      该SQL近期未执行成功,资源消耗不用看也一定很高。


      04

       问题分析及优化思路 

      通过分析SQL文本,发现该SQL是一个典型的利用开窗来去重数据,但过滤条件在最后,先开窗再过滤的逻辑。

      通过分析执行计划,TBL_001走全表扫描做开窗运算,而该表的体积近13GB,需要使用的TEMP空间近18GB,再和其它两张表进行HASH JOIN,这就导致该SQL执行效率非常低。

      结合以上分析,该SQL通过创建的索引是无法优化的,只能通过改写SQL来优化,一是结合业务逻辑,TBL_001.d_001是否可以提前过滤,好处是可以利用到索引,坏处就是SQL逻辑不等价,只能是业务逻辑等价。二是通过等价改写SQL,难度较大。


      05

       优化方案 

      1. 提前过滤方案

      理想情况是针对核对大表提前过滤,但这样不等价,以下实验过程将证明这点

      1)创建测试表

        -- 创建Z表
        CREATE TABLE Z (
          ID NUMBER PRIMARY KEY,
          LOT_CODE VARCHAR2(10),
          STRIP_CODE VARCHAR2(10),
          WAFER_CODE VARCHAR2(10),
          POS_X NUMBER,
          POS_Y NUMBER,
          FUNC_X VARCHAR2(10),
          FUNC_Y VARCHAR2(10),
          MARK_CODE VARCHAR2(10),
          CREATE_TIME DATE
        );
        -- 创建C表
        CREATE TABLE C (
          LOT_CODE VARCHAR2(10),
          STRIP_CODE VARCHAR2(10),
          FUNC_X VARCHAR2(10),
          FUNC_Y VARCHAR2(10),
          WAFER_ROW NUMBER,
          WAFER_COL NUMBER,
          ORIENTATION NUMBER,
          DIE_CODE VARCHAR2(10),
          WAFER_ID VARCHAR2(10)
        );
        -- 创建B表
        CREATE TABLE B (
          LOT_CODE VARCHAR2(10),
          STRIP_CODE VARCHAR2(10),
          FUNC_X VARCHAR2(10),
          FUNC_Y VARCHAR2(10),
          CURR_PROC NUMBER,
          PROCESS NUMBER
        );


        2)插入测试数据

          -- 分区1:有两条记录,ID=1时间不符合,ID=2时间符合
          INSERT INTO Z (ID, LOT_CODE, STRIP_CODE, WAFER_CODE, POS_X, POS_Y, FUNC_X, FUNC_Y, MARK_CODE, CREATE_TIME)
          VALUES (1'LOT1001''STRIP01''WAFER01'11'FX01''FY01''MARKA', TRUNC(SYSDATE) - 2);
          INSERT INTO Z (ID, LOT_CODE, STRIP_CODE, WAFER_CODE, POS_X, POS_Y, FUNC_X, FUNC_Y, MARK_CODE, CREATE_TIME)
          VALUES (2'LOT1001''STRIP01''WAFER01'11'FX01''FY01''MARKB', TRUNC(SYSDATE) - 0.5);
          -- 分区2:仅有一条记录,时间符合
          INSERT INTO Z (ID, LOT_CODE, STRIP_CODE, WAFER_CODE, POS_X, POS_Y, FUNC_X, FUNC_Y, MARK_CODE, CREATE_TIME)
          VALUES (3'LOT1002''STRIP02''WAFER02'22'FX02''FY02''MARKC', TRUNC(SYSDATE) - 0.5);
          -- C表关联数据
          INSERT INTO C (LOT_CODE, STRIP_CODE, FUNC_X, FUNC_Y, WAFER_ROW, WAFER_COL, ORIENTATION, DIE_CODE, WAFER_ID)
          VALUES ('LOT1001''STRIP01''FX01''FY01'10200'DIE001''WAF001');
          INSERT INTO C (LOT_CODE, STRIP_CODE, FUNC_X, FUNC_Y, WAFER_ROW, WAFER_COL, ORIENTATION, DIE_CODE, WAFER_ID)
          VALUES ('LOT1002''STRIP02''FX02''FY02'15250'DIE002''WAF002');
          -- B表关联数据
          INSERT INTO B (LOT_CODE, STRIP_CODE, FUNC_X, FUNC_Y, CURR_PROC, PROCESS)
          VALUES ('LOT1001''STRIP01''FX01''FY01'44);
          INSERT INTO B (LOT_CODE, STRIP_CODE, FUNC_X, FUNC_Y, CURR_PROC, PROCESS)
          VALUES ('LOT1002''STRIP02''FX02''FY02'54);


          3)原 SQL 执行(全量开窗 + 后过滤)

            -- 执行SQL
            SELECT 
              a.LOT_CODE,
              a.STRIP_CODE,
              a.FUNC_X,
              a.FUNC_Y,
              a.MARK_CODE,
              a.CREATE_TIME,
              a.rn
            FROM (
              SELECT 
                z.LOT_CODE,
                z.STRIP_CODE,
                z.FUNC_X,
                z.FUNC_Y,
                z.MARK_CODE,
                z.CREATE_TIME,
                ROW_NUMBER() OVER (
                  PARTITION BY z.LOT_CODE, z.STRIP_CODE, z.WAFER_CODE, z.FUNC_X, z.FUNC_Y 
                  ORDER BY z.ID
                ) AS rn
              FROM Z z
            ) a
            INNER JOIN C c 
              ON a.LOT_CODE = c.LOT_CODE 
              AND a.STRIP_CODE = c.STRIP_CODE 
              AND a.FUNC_X = c.FUNC_X 
              AND a.FUNC_Y = c.FUNC_Y
            INNER JOIN B b 
              ON a.LOT_CODE = b.LOT_CODE 
              AND a.STRIP_CODE = b.STRIP_CODE 
              AND a.FUNC_X = b.FUNC_X 
              AND a.FUNC_Y = b.FUNC_Y
            WHERE a.rn = 1
              AND b.PROCESS = 4
              AND c.WAFER_ID IS NOT NULL
              AND a.CREATE_TIME >= TRUNC(SYSDATE) - 1
              AND a.CREATE_TIME < TRUNC(SYSDATE);


            4)结果及执行计划

              LOT_CODE   STRIP_CODE FUNC_X     FUNC_Y     MARK_CODE  CREATE_TI         RN
              ---------- ---------- ---------- ---------- ---------- --------- ----------
              LOT1002    STRIP02    FX02       FY02       MARKC      09-JUN-25          1
              Execution Plan
              ----------------------------------------------------------
              Plan hash value966504544
              ----------------------------------------------------------------------------------
              | Id  | Operation                 | Name | Rows  | Bytes | Cost (%CPU)| Time     |
              ----------------------------------------------------------------------------------
              |   0 | SELECT STATEMENT          |      |     1 |   133 |     7  (15)| 00:00:01 |
              |*  1 |  HASH JOIN                |      |     1 |   133 |     7  (15)| 00:00:01 |
              |   2 |   MERGE JOIN CARTESIAN    |      |     4 |   304 |     4   (0)| 00:00:01 |
              |*  3 |    TABLE ACCESS FULL      | C    |     2 |    70 |     2   (0)| 00:00:01 |
              |   4 |    BUFFER SORT            |      |     2 |    82 |     2   (0)| 00:00:01 |
              |*  5 |     TABLE ACCESS FULL     | B    |     2 |    82 |     1   (0)| 00:00:01 |
              |*  6 |   VIEW                    |      |     3 |   171 |     3  (34)| 00:00:01 |
              |*  7 |    WINDOW SORT PUSHED RANK|      |     3 |   192 |     3  (34)| 00:00:01 |
              |*  8 |     FILTER                |      |       |       |            |          |
              |   9 |      TABLE ACCESS FULL    | Z    |     3 |   192 |     2   (0)| 00:00:01 |
              ----------------------------------------------------------------------------------
              Predicate Information (identified by operation id):
              ---------------------------------------------------
                 1 - access("A"."LOT_CODE"="B"."LOT_CODE" AND
                            "A"."STRIP_CODE"="B"."STRIP_CODE" AND "A"."FUNC_X"="B"."FUNC_X" AND
                            "A"."FUNC_Y"="B"."FUNC_Y" AND "A"."LOT_CODE"="C"."LOT_CODE" AND
                            "A"."STRIP_CODE"="C"."STRIP_CODE" AND "A"."FUNC_X"="C"."FUNC_X" AND
                            "A"."FUNC_Y"="C"."FUNC_Y")
                 3 - filter("C"."WAFER_ID" IS NOT NULL)
                 5 - filter("B"."PROCESS"=4)
                 6 - filter("A"."RN"=1 AND "A"."CREATE_TIME">=TRUNC(SYSDATE@!)-1 AND
                            "A"."CREATE_TIME"<TRUNC(SYSDATE@!))
                 7 - filter(ROW_NUMBER() OVER ( PARTITION BY
                            "Z"."LOT_CODE","Z"."STRIP_CODE","Z"."WAFER_CODE","Z"."FUNC_X","Z"."FUNC_Y"
                             ORDER BY "Z"."ID")<=1)
                 8 - filter(TRUNC(SYSDATE@!)>TRUNC(SYSDATE@!)-1)


              5)改写后 SQL 执行(先过滤 + 再开窗)

                -- 执行改写后的SQL逻辑
                WITH filtered_z AS (
                  SELECT * 
                  FROM Z 
                  WHERE CREATE_TIME >= TRUNC(SYSDATE) - 1
                    AND CREATE_TIME < TRUNC(SYSDATE)
                ),
                ranked_z AS (
                  SELECT 
                    z.LOT_CODE,
                    z.STRIP_CODE,
                    z.FUNC_X,
                    z.FUNC_Y,
                    z.MARK_CODE,
                    z.CREATE_TIME,
                    ROW_NUMBER() OVER (
                      PARTITION BY z.LOT_CODE, z.STRIP_CODE, z.WAFER_CODE, z.FUNC_X, z.FUNC_Y 
                      ORDER BY z.ID
                    ) AS rn
                  FROM filtered_z z
                )
                SELECT 
                  a.LOT_CODE,
                  a.STRIP_CODE,
                  a.FUNC_X,
                  a.FUNC_Y,
                  a.MARK_CODE,
                  a.CREATE_TIME,
                  a.rn
                FROM ranked_z a
                INNER JOIN C c 
                  ON a.LOT_CODE = c.LOT_CODE 
                  AND a.STRIP_CODE = c.STRIP_CODE 
                  AND a.FUNC_X = c.FUNC_X 
                  AND a.FUNC_Y = c.FUNC_Y
                INNER JOIN B b 
                  ON a.LOT_CODE = b.LOT_CODE 
                  AND a.STRIP_CODE = b.STRIP_CODE 
                  AND a.FUNC_X = b.FUNC_X 
                  AND a.FUNC_Y = b.FUNC_Y
                WHERE a.rn = 1
                  AND b.PROCESS = 4
                  AND c.WAFER_ID IS NOT NULL;

                这样的改写还有另一个好处,由于过滤条件是查前1天的数据,大概率是可以利用到索引,让整个执行计划走NL,就是非常理解的情况了。


                6)结果及执行计划

                  LOT_CODE   STRIP_CODE FUNC_X     FUNC_Y     MARK_CODE  CREATE_TI         RN
                  ---------- ---------- ---------- ---------- ---------- --------- ----------
                  LOT1001    STRIP01    FX01       FY01       MARKB      09-JUN-25          1
                  LOT1002    STRIP02    FX02       FY02       MARKC      09-JUN-25          1
                  Execution Plan
                  ----------------------------------------------------------
                  Plan hash value966504544
                  ----------------------------------------------------------------------------------
                  | Id  | Operation                 | Name | Rows  | Bytes | Cost (%CPU)| Time     |
                  ----------------------------------------------------------------------------------
                  |   0 | SELECT STATEMENT          |      |     2 |   266 |     7  (15)| 00:00:01 |
                  |*  1 |  HASH JOIN                |      |     2 |   266 |     7  (15)| 00:00:01 |
                  |   2 |   MERGE JOIN CARTESIAN    |      |     4 |   304 |     4   (0)| 00:00:01 |
                  |*  3 |    TABLE ACCESS FULL      | C    |     2 |    70 |     2   (0)| 00:00:01 |
                  |   4 |    BUFFER SORT            |      |     2 |    82 |     2   (0)| 00:00:01 |
                  |*  5 |     TABLE ACCESS FULL     | B    |     2 |    82 |     1   (0)| 00:00:01 |
                  |*  6 |   VIEW                    |      |     2 |   114 |     3  (34)| 00:00:01 |
                  |*  7 |    WINDOW SORT PUSHED RANK|      |     2 |   128 |     3  (34)| 00:00:01 |
                  |*  8 |     FILTER                |      |       |       |            |          |
                  |*  9 |      TABLE ACCESS FULL    | Z    |     2 |   128 |     2   (0)| 00:00:01 |
                  ----------------------------------------------------------------------------------
                  Predicate Information (identified by operation id):
                  ---------------------------------------------------
                     1 - access("A"."LOT_CODE"="B"."LOT_CODE" AND
                                "A"."STRIP_CODE"="B"."STRIP_CODE" AND "A"."FUNC_X"="B"."FUNC_X" AND
                                "A"."FUNC_Y"="B"."FUNC_Y" AND "A"."LOT_CODE"="C"."LOT_CODE" AND
                                "A"."STRIP_CODE"="C"."STRIP_CODE" AND "A"."FUNC_X"="C"."FUNC_X" AND
                                "A"."FUNC_Y"="C"."FUNC_Y")
                     3 - filter("C"."WAFER_ID" IS NOT NULL)
                     5 - filter("B"."PROCESS"=4)
                     6 - filter("A"."RN"=1)
                     7 - filter(ROW_NUMBER() OVER ( PARTITION BY
                                "Z"."LOT_CODE","Z"."STRIP_CODE","Z"."WAFER_CODE","Z"."FUNC_X","Z"."FUNC_Y"
                                 ORDER BY "Z"."ID")<=1)
                     8 - filter(TRUNC(SYSDATE@!)>TRUNC(SYSDATE@!)-1)
                     9 - filter("CREATE_TIME"<TRUNC(SYSDATE@!AND
                                "CREATE_TIME">=TRUNC(SYSDATE@!)-1)

                  从上面的实验可以看出,这样改写并不等价,所以这个方案并不可取。


                  7)关键差异分析

                  不等价原因

                  原 SQL 中,符合时间条件的记录(ID=2)因rn=2被过滤;而改写后,由于提前过滤了时间,ID=2 变为rn=1,导致结果集差异。


                  2. 如何等价改写

                  1)not exits改写

                  若需保留逻辑等价性,可改为半连接过滤(避免开窗函数):

                    SELECT 
                      z.LOT_CODE,
                      z.STRIP_CODE,
                      z.FUNC_X,
                      z.FUNC_Y,
                      z.MARK_CODE,
                      z.CREATE_TIME
                    FROM Z z
                    INNER JOIN C c 
                      ON z.LOT_CODE = c.LOT_CODE 
                      AND z.STRIP_CODE = c.STRIP_CODE 
                      AND z.FUNC_X = c.FUNC_X 
                      AND z.FUNC_Y = c.FUNC_Y
                    INNER JOIN B b 
                      ON z.LOT_CODE = b.LOT_CODE 
                      AND z.STRIP_CODE = b.STRIP_CODE 
                      AND z.FUNC_X = b.FUNC_X 
                      AND z.FUNC_Y = b.FUNC_Y
                    WHERE z.CREATE_TIME >= TRUNC(SYSDATE) - 1
                      AND z.CREATE_TIME < TRUNC(SYSDATE)
                      AND b.PROCESS = 4
                      AND c.WAFER_ID IS NOT NULL
                      AND NOT EXISTS (
                        SELECT 1 
                        FROM Z z2 
                        WHERE z2.LOT_CODE = z.LOT_CODE 
                          AND z2.STRIP_CODE = z.STRIP_CODE 
                          AND z2.WAFER_CODE = z.WAFER_CODE 
                          AND z2.FUNC_X = z.FUNC_X 
                          AND z2.FUNC_Y = z.FUNC_Y 
                          AND z2.ID < z.ID
                      );

                    此方案通过NOT EXISTS确保每条记录是分区内 ID 最小的(等价于rn=1),同时提前过滤时间,避免全表扫描,推荐使用该方案。


                    2)结果及执行计划

                      LOT_CODE   STRIP_CODE FUNC_X     FUNC_Y     MARK_CODE  CREATE_TI
                      ---------- ---------- ---------- ---------- ---------- ---------
                      LOT1002    STRIP02    FX02       FY02       MARKC      09-JUN-25
                      Execution Plan
                      ----------------------------------------------------------
                      Plan hash value1558471538
                      --------------------------------------------------------------------------------
                      | Id  | Operation               | Name | Rows  | Bytes | Cost (%CPU)| Time     |
                      --------------------------------------------------------------------------------
                      |   0 | SELECT STATEMENT        |      |     2 |   376 |     8   (0)| 00:00:01 |
                      |*  1 |  FILTER                 |      |       |       |            |          |
                      |*  2 |   HASH JOIN ANTI        |      |     2 |   376 |     8   (0)| 00:00:01 |
                      |*  3 |    HASH JOIN            |      |     2 |   280 |     6   (0)| 00:00:01 |
                      |   4 |     MERGE JOIN CARTESIAN|      |     4 |   304 |     4   (0)| 00:00:01 |
                      |*  5 |      TABLE ACCESS FULL  | C    |     2 |    70 |     2   (0)| 00:00:01 |
                      |   6 |      BUFFER SORT        |      |     2 |    82 |     2   (0)| 00:00:01 |
                      |*  7 |       TABLE ACCESS FULL | B    |     2 |    82 |     1   (0)| 00:00:01 |
                      |*  8 |     TABLE ACCESS FULL   | Z    |     2 |   128 |     2   (0)| 00:00:01 |
                      |   9 |    TABLE ACCESS FULL    | Z    |     3 |   144 |     2   (0)| 00:00:01 |
                      --------------------------------------------------------------------------------
                      Predicate Information (identified by operation id):
                      ---------------------------------------------------
                         1 - filter(TRUNC(SYSDATE@!)>TRUNC(SYSDATE@!)-1)
                         2 - access("Z2"."LOT_CODE"="Z"."LOT_CODE" AND
                                    "Z2"."STRIP_CODE"="Z"."STRIP_CODE" AND
                                    "Z2"."WAFER_CODE"="Z"."WAFER_CODE" AND "Z2"."FUNC_X"="Z"."FUNC_X" AND
                                    "Z2"."FUNC_Y"="Z"."FUNC_Y")
                             filter("Z2"."ID"<"Z"."ID")
                         3 - access("Z"."LOT_CODE"="B"."LOT_CODE" AND
                                    "Z"."STRIP_CODE"="B"."STRIP_CODE" AND "Z"."FUNC_X"="B"."FUNC_X" AND
                                    "Z"."FUNC_Y"="B"."FUNC_Y" AND "Z"."LOT_CODE"="C"."LOT_CODE" AND
                                    "Z"."STRIP_CODE"="C"."STRIP_CODE" AND "Z"."FUNC_X"="C"."FUNC_X" AND
                                    "Z"."FUNC_Y"="C"."FUNC_Y")
                         5 - filter("C"."WAFER_ID" IS NOT NULL)
                         7 - filter("B"."PROCESS"=4)
                         8 - filter("Z"."CREATE_TIME"<TRUNC(SYSDATE@!AND
                                    "Z"."CREATE_TIME">=TRUNC(SYSDATE@!)-1)

                      写在最后


                      改写SQL的重要性在于,通过优化查询逻辑与执行计划,可显著提升数据库性能、降低资源消耗并确保业务逻辑的准确性——如案例中原始SQL因窗口函数未提前过滤时间条件,导致全表扫描与高额临时空间消耗(18G),而通过将窗口函数改写为NOT EXISTS结合索引优化,不仅避免了无效数据排序,还将执行成本从14M降至150K,在保证查询结果等价的前提下,实现了资源利用率与执行效率的数量级提升,充分体现了SQL改写对系统性能优化的核心价值。

                      作者介绍

                      大家好,我是刘峰,安丫科技创始人 & 数据库技术高级讲师,专注于 PostgreSQL、国产数据库运维与迁移、数据库性能优化 等方向。

                      作为 PG中国分会官方授权讲师、PostgreSQL ACE 讲师认证专家,我长期活跃在一线项目实战中,拥有 10年以上大型数据库管理与优化经验,曾深度参与电信、金融、政务等多个行业的数据库性能调优与迁移项目。

                      欢迎关注我,一起深入探索数据库的无限可能,技术交流不设限!

                      📌 觉得有收获的话,记得点赞、收藏、转发支持一下哦,别忘了关注我获取更多数据库干货~


                      END

                      关键词回复(可见相应文章):

                      oracle、mysql、pg、postgresql、sql、性能优化、故障处理、数据迁移、备份恢复、版本升级、补丁管理、深度巡检、解决方案、架构设计......

                      小助手

                      有任何问题或疑问,欢迎加V进群探讨哦~


                      \ | /

                      动动你的手指

                      【安呀智数据坊】加个星标吧~

                      这样你就不会丢下我啦~

                      记得加星标呀!

                      文章转载自安呀智数据坊,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                      评论