【问题标题】:I want to fine tune a query which is taking more then 3-5 hours on the database我想微调在数据库上花费超过 3-5 小时的查询
【发布时间】:2015-07-29 18:40:14
【问题描述】:

我想微调以下在数据库上运行需要很长时间的查询。查询如下:

SELECT
  RSE.RSE_CD_D_BRANCH.FIN_DIVISION_CODE,
  RSE.RSE_CD_D_PRODUCT_BRANCH_CUR.BUYER,
  RSE.RSE_CD_D_PRODUCT_FLAT.BUY_LINE,
  RSE.RSE_CD_D_BRANCH.FIN_BRANCH_CODE,
  RSE.RSE_CD_D_BRANCH.BRANCH_NUMBER,
  RSE.RSE_CD_D_PRODUCT_FLAT.PRODUCT_NUMBER,
  NVL(RSE.RSE_CD_D_PRODUCT_FLAT.PRODUCT_DESC,RSE.RSE_CD_D_PRODUCT_FLAT.PRODUCT_DESC_LONG),
  SUM(RSE.RSE_IV_F_VALUATION_SV.ON_HAND_QTY),
  SUM(RSE.RSE_IV_F_VALUATION_SV.COMMITTED_QTY),
  SUM(RSE.RSE_IV_F_VALUATION_SV.COMMITTED_QTY_RAW),
  SUM(RSE.RSE_IV_F_VALUATION_SV.DEMAND_PER_DAY_ECL_HUB),
  SUM(RSE.RSE_IV_F_VALUATION_SV.INBOUND_RECEIPT_QTY),
  RSE.RSE_IV_F_VALUATION_SV.BRANCH_STOCK_FLAG,
  RSE.RSE_CD_D_PRODUCT_BRANCH_CUR.TOP_200_ITEM_FLAG,
  SUBSTR(RSE.RSE_CD_D_PRODUCT_BRANCH_CUR.FULL_ISO,3,2),
  RSE.RSE_CD_D_PRODUCT_BRANCH_CUR.ORDER_PNT_XFER_PNT
FROM
  RSE.RSE_CD_D_BRANCH,
  RSE.RSE_CD_D_PRODUCT_BRANCH_CUR,
  RSE.RSE_CD_D_PRODUCT_FLAT,
  RSE.RSE_IV_F_VALUATION_SV,
  RSE.RSE_CD_D_CALENDAR
WHERE
  ( RSE.RSE_CD_D_BRANCH.DW_BRANCH_ID=RSE.RSE_IV_F_VALUATION_SV.DW_BRANCH_ID  )
  AND  ( RSE.RSE_CD_D_CALENDAR.CALENDAR_DATE=RSE.RSE_IV_F_VALUATION_SV.VALUATION_DATE  )
  AND  ( RSE.RSE_CD_D_PRODUCT_FLAT.PRODUCT_ID=RSE.RSE_IV_F_VALUATION_SV.PRODUCT_ID  )
  AND  ( RSE.RSE_CD_D_PRODUCT_BRANCH_CUR.PRODUCT_ID=RSE.RSE_IV_F_VALUATION_SV.PRODUCT_ID and RSE.RSE_CD_D_PRODUCT_BRANCH_CUR.DW_BRANCH_ID=RSE.RSE_IV_F_VALUATION_SV.DW_BRANCH_ID  )
  AND  ( RSE.RSE_IV_F_VALUATION_SV.SSO_ID= '570000018'  )
  AND  
  (
   RSE.RSE_CD_D_CALENDAR.DAY_RELATIVE  =  0
   AND
   RSE.RSE_CD_D_BRANCH.BRANCH_NUMBER  NOT IN  ( '1167','2305','1581','3129','1075','1078','7995'  )
   AND
   RSE.RSE_CD_D_PRODUCT_BRANCH_CUR.ORDER_PNT_XFER_PNT  >  0
   AND
   RSE.RSE_IV_F_VALUATION_SV.LOCATION_TYPE_DESC  IN  ( 'CONSIGNMENT','STOCK','PREVIEW QUEUE','TAGGED'  )
   AND
   CASE WHEN RSE.RSE_CD_D_PRODUCT_BRANCH_CUR.BASE_STOCK_FLAG = '0' THEN 'N' WHEN RSE.RSE_CD_D_PRODUCT_BRANCH_CUR.BASE_STOCK_FLAG = '1' THEN 'Y' ELSE 'AUTO' END  IN  ( 'AUTO','Y'  )
   AND
   RSE.RSE_CD_D_PRODUCT_FLAT.PRODUCT_STATUS_DESC  IN  ( 'Stock'  )
   AND
   RSE.RSE_CD_D_PRODUCT_BRANCH_CUR.FULL_ISO  IN  ( 'S.A','S.A1','S.A2','S.A3','S.A4','S.B','S.B1','S.B2','S.B3','S.B4','S.NA','S.NB','S.NS','S.S','S.S1','S.S2','S.S3','S.S4','S.T2','S.T3'  )
  )
GROUP BY
  RSE.RSE_CD_D_BRANCH.FIN_DIVISION_CODE, 
  RSE.RSE_CD_D_PRODUCT_BRANCH_CUR.BUYER, 
  RSE.RSE_CD_D_PRODUCT_FLAT.BUY_LINE, 
  RSE.RSE_CD_D_BRANCH.FIN_BRANCH_CODE, 
  RSE.RSE_CD_D_BRANCH.BRANCH_NUMBER, 
  RSE.RSE_CD_D_PRODUCT_FLAT.PRODUCT_NUMBER, 
  NVL(RSE.RSE_CD_D_PRODUCT_FLAT.PRODUCT_DESC,RSE.RSE_CD_D_PRODUCT_FLAT.PRODUCT_DESC_LONG), 
  RSE.RSE_IV_F_VALUATION_SV.BRANCH_STOCK_FLAG, 
  RSE.RSE_CD_D_PRODUCT_BRANCH_CUR.TOP_200_ITEM_FLAG, 
  SUBSTR(RSE.RSE_CD_D_PRODUCT_BRANCH_CUR.FULL_ISO,3,2), 
  RSE.RSE_CD_D_PRODUCT_BRANCH_CUR.ORDER_PNT_XFER_PNT
HAVING
  SUM(RSE.RSE_IV_F_VALUATION_SV.DEMAND_PER_DAY_ECL_HUB)  >  0;

以下是解释计划:

Plan hash value: 2631612456

-----------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                 | Name                        | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                          |                             |     1 |   215 |   479K  (1)| 01:35:59 |       |       |
|*  1 |  FILTER                                   |                             |       |       |            |          |       |       |
|   2 |   HASH GROUP BY                           |                             |     1 |   215 |   479K  (1)| 01:35:59 |       |       |
|   3 |    NESTED LOOPS                           |                             |       |       |            |          |       |       |
|   4 |     NESTED LOOPS                          |                             |     1 |   215 |   479K  (1)| 01:35:59 |       |       |
|   5 |      NESTED LOOPS                         |                             |     1 |   116 |   479K  (1)| 01:35:59 |       |       |
|   6 |       NESTED LOOPS                        |                             |     1 |    97 |   479K  (1)| 01:35:59 |       |       |
|*  7 |        HASH JOIN                          |                             |     1 |    82 |   479K  (1)| 01:35:58 |       |       |
|   8 |         TABLE ACCESS BY INDEX ROWID       | RSE_CD_D_CALENDAR           |     1 |    13 |     2   (0)| 00:00:01 |       |       |
|*  9 |          INDEX RANGE SCAN                 | RSE_CD_D_CALENDAR_I5        |     1 |       |     1   (0)| 00:00:01 |       |       |
|  10 |         NESTED LOOPS                      |                             |       |       |            |          |       |       |
|  11 |          NESTED LOOPS                     |                             |   173 | 11937 |   479K  (1)| 01:35:58 |       |       |
|  12 |           INLIST ITERATOR                 |                             |       |       |            |          |       |       |
|* 13 |            TABLE ACCESS BY INDEX ROWID    | RSE_CD_D_PRODUCT_BRANCH_CUR |   147 |  4263 | 48731   (1)| 00:09:45 |       |       |
|* 14 |             INDEX RANGE SCAN              | RSE_CD_D_PROD_BRANC_CUR_I2  |   208K|       |   602   (1)| 00:00:08 |       |       |
|  15 |           PARTITION RANGE ALL             |                             |     1 |       |  2932   (1)| 00:00:36 |     1 |  1465 |
|* 16 |            INDEX RANGE SCAN               | RSE_IV_F_VALUATION_I5       |     1 |       |  2932   (1)| 00:00:36 |     1 |  1465 |
|* 17 |          TABLE ACCESS BY LOCAL INDEX ROWID| RSE_IV_F_VALUATION          |     1 |    40 |  2933   (1)| 00:00:36 |     1 |     1 |
|* 18 |        TABLE ACCESS BY INDEX ROWID        | RSE_IV_D_SECURITY_BRANCH    |     1 |    15 |     5   (0)| 00:00:01 |       |       |
|* 19 |         INDEX RANGE SCAN                  | RSE_IV_D_SECURITY_BRANCH_I2 |   580 |       |     1   (0)| 00:00:01 |       |       |
|* 20 |       TABLE ACCESS BY INDEX ROWID         | RSE_CD_D_BRANCH             |     1 |    19 |     1   (0)| 00:00:01 |       |       |
|* 21 |        INDEX UNIQUE SCAN                  | RSE_CD_D_BRANCH_PK          |     1 |       |     0   (0)| 00:00:01 |       |       |
|* 22 |      INDEX UNIQUE SCAN                    | RSE_CD_PRODUCT_FLAT_PK      |     1 |       |     1   (0)| 00:00:01 |       |       |
|* 23 |     TABLE ACCESS BY INDEX ROWID           | RSE_CD_D_PRODUCT_FLAT       |     1 |    99 |     2   (0)| 00:00:01 |       |       |
-----------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(SUM("A"."DEMAND_PER_DAY_ECL_HUB")>0)
   7 - access("RSE_CD_D_CALENDAR"."CALENDAR_DATE"="A"."VALUATION_DATE")
   9 - access("RSE_CD_D_CALENDAR"."DAY_RELATIVE"=0)
  13 - filter("RSE_CD_D_PRODUCT_BRANCH_CUR"."ORDER_PNT_XFER_PNT">0 AND (CASE "RSE_CD_D_PRODUCT_BRANCH_CUR"."BASE_STOCK_FLAG" 
              WHEN '0' THEN 'N' WHEN '1' THEN 'Y' ELSE 'AUTO' END ='AUTO' OR CASE "RSE_CD_D_PRODUCT_BRANCH_CUR"."BASE_STOCK_FLAG" WHEN '0' 
              THEN 'N' WHEN '1' THEN 'Y' ELSE 'AUTO' END ='Y'))
  14 - access("RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.A' OR "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.A1' OR 
              "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.A2' OR "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.A3' OR 
              "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.A4' OR "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.B' OR 
              "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.B1' OR "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.B2' OR 
              "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.B3' OR "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.B4' OR 
              "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.NA' OR "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.NB' OR 
              "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.NS' OR "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.S' OR 
              "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.S1' OR "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.S2' OR 
              "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.S3' OR "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.S4' OR 
              "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.T2' OR "RSE_CD_D_PRODUCT_BRANCH_CUR"."FULL_ISO"='S.T3')
  16 - access("RSE_CD_D_PRODUCT_BRANCH_CUR"."DW_BRANCH_ID"="A"."DW_BRANCH_ID" AND 
              "RSE_CD_D_PRODUCT_BRANCH_CUR"."PRODUCT_ID"="A"."PRODUCT_ID")
  17 - filter("A"."LOCATION_TYPE_DESC"='CONSIGNMENT' OR "A"."LOCATION_TYPE_DESC"='PREVIEW QUEUE' OR 
              "A"."LOCATION_TYPE_DESC"='STOCK' OR "A"."LOCATION_TYPE_DESC"='TAGGED')
  18 - filter("B"."SSO_ID"='570000018')
  19 - access("A"."DW_BRANCH_ID"="B"."DW_BRANCH_ID")
  20 - filter("RSE_CD_D_BRANCH"."BRANCH_NUMBER"<>'1167' AND "RSE_CD_D_BRANCH"."BRANCH_NUMBER"<>'2305' AND 
              "RSE_CD_D_BRANCH"."BRANCH_NUMBER"<>'1581' AND "RSE_CD_D_BRANCH"."BRANCH_NUMBER"<>'3129' AND 
              "RSE_CD_D_BRANCH"."BRANCH_NUMBER"<>'1075' AND "RSE_CD_D_BRANCH"."BRANCH_NUMBER"<>'1078' AND 
              "RSE_CD_D_BRANCH"."BRANCH_NUMBER"<>'7995')
  21 - access("RSE_CD_D_BRANCH"."DW_BRANCH_ID"="A"."DW_BRANCH_ID")
  22 - access("RSE_CD_D_PRODUCT_FLAT"."PRODUCT_ID"="A"."PRODUCT_ID")
  23 - filter("RSE_CD_D_PRODUCT_FLAT"."PRODUCT_STATUS_DESC"='Stock')

估价日期没有索引,但日期有分区,我无法找到我还能做什么,以便查询花费更少的时间

【问题讨论】:

  • 查询访问分区表 RSE_IV_F_VALUATION 的所有分区。我不知道这个查询的目的,但真的有必要访问所有分区吗?该表按哪个列分区?也许按目的查询必须访问所有分区 - 但也许不是。

标签: sql oracle oracle11g oracle10g query-performance


【解决方案1】:

创建expression statistic 可能会显着改善CASE 谓词的基数估计,然后会导致解释计划的其他改进。


找到真正的问题

首先,您应该验证真正的问题出在哪里。你知道查询很慢,但是查询的什么操作很慢?像实时 SQL 监控这样的工具 会很快回答这个问题。运行类似select dbms_sqltune.report_sql_monitor(sql_id =&gt; 'your sql_id', type =&gt; 'text'; 的语句。查看 Activity % 以了解哪个步骤花费的时间最长。

我猜您还会看到计划 ID 13 的估计行数和实际行数之间存在巨大差异。该列是一个“标志”,我假设返回的行数比估计的 147 行多。然后这个小估计导致NESTED LOOPS 而不是HASH JOINS。解决原来的基数问题可能会解决其他问题。

示例架构和错误的基数估计

下面的代码创建了一个倾斜的标志列。

--drop table RSE_CD_D_PRODUCT_BRANCH_CUR;
create table RSE_CD_D_PRODUCT_BRANCH_CUR(BASE_STOCK_FLAG varchar2(100));
insert into RSE_CD_D_PRODUCT_BRANCH_CUR select '0' from dual connect by level <= 10;
insert into RSE_CD_D_PRODUCT_BRANCH_CUR select '1' from dual connect by level <= 5000;
insert into RSE_CD_D_PRODUCT_BRANCH_CUR select '2' from dual connect by level <= 5000;

begin
    dbms_stats.gather_table_stats(user, 'RSE_CD_D_PRODUCT_BRANCH_CUR');
end;
/

下面的查询返回 10,000 行。但优化器认为它只会返回 199。

explain plan for
select *
from RSE_CD_D_PRODUCT_BRANCH_CUR
WHERE
    CASE
        WHEN BASE_STOCK_FLAG = '0' THEN 'N'
        WHEN BASE_STOCK_FLAG = '1' THEN 'Y'
        ELSE 'AUTO'
    END IN ( 'AUTO','Y'  );

select * from table(dbms_xplan.display);

Plan hash value: 1579167612

-------------------------------------------------------------------------------------------------
| Id  | Operation         | Name                        | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                             |   199 |   398 |     5   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| RSE_CD_D_PRODUCT_BRANCH_CUR |   199 |   398 |     5   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(CASE "BASE_STOCK_FLAG" WHEN '0' THEN 'N' WHEN '1' THEN 'Y' ELSE 'AUTO' END 
              ='AUTO' OR CASE "BASE_STOCK_FLAG" WHEN '0' THEN 'N' WHEN '1' THEN 'Y' ELSE 'AUTO' END 
              ='Y')

创建表达式统计

使用解释计划中的谓词生成表达式统计信息。这就像创建一个单独的列,只包含将要过滤的结果,并允许 Oracle 做出更好的估计。

select dbms_stats.create_extended_stats(user, 'RSE_CD_D_PRODUCT_BRANCH_CUR', q'{(CASE "BASE_STOCK_FLAG" WHEN '0' THEN 'N' WHEN '1' THEN 'Y' ELSE 'AUTO' END)}')
from dual;

SYS_STU23HKS830RX09S$M3L713_6_

现在重新收集统计数据,估计值更接近 - 6673 行而不是 199 行。

begin
    dbms_stats.gather_table_stats(user, 'RSE_CD_D_PRODUCT_BRANCH_CUR');
end;
/

explain plan for
select *
from RSE_CD_D_PRODUCT_BRANCH_CUR
WHERE
    CASE
        WHEN BASE_STOCK_FLAG = '0' THEN 'N'
        WHEN BASE_STOCK_FLAG = '1' THEN 'Y'
        ELSE 'AUTO'
    END IN ( 'AUTO','Y'  );

select * from table(dbms_xplan.display);

Plan hash value: 1579167612

-------------------------------------------------------------------------------------------------
| Id  | Operation         | Name                        | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                             |  6673 | 33365 |     5   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| RSE_CD_D_PRODUCT_BRANCH_CUR |  6673 | 33365 |     5   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(CASE "BASE_STOCK_FLAG" WHEN '0' THEN 'N' WHEN '1' THEN 'Y' ELSE 'AUTO' END 
              ='AUTO' OR CASE "BASE_STOCK_FLAG" WHEN '0' THEN 'N' WHEN '1' THEN 'Y' ELSE 'AUTO' END 
              ='Y')

再来一次直方图。

您可能必须重新运行 SELECT 语句并再次重新收集统计信息以生成直方图。直方图可以提供更好的结果。重新运行是必要的,因为 Oracle 不会在以前没有用的列上收集直方图。 (当您想到所有不需要直方图的审计列时,这是有道理的。)

现在估计是完美的 10,000 行。

select *
from RSE_CD_D_PRODUCT_BRANCH_CUR
WHERE
    CASE
        WHEN BASE_STOCK_FLAG = '0' THEN 'N'
        WHEN BASE_STOCK_FLAG = '1' THEN 'Y'
        ELSE 'AUTO'
    END IN ( 'AUTO','Y'  );

begin
    dbms_stats.gather_table_stats(user, 'RSE_CD_D_PRODUCT_BRANCH_CUR');
end;
/

explain plan for
select *
from RSE_CD_D_PRODUCT_BRANCH_CUR
WHERE
    CASE
        WHEN BASE_STOCK_FLAG = '0' THEN 'N'
        WHEN BASE_STOCK_FLAG = '1' THEN 'Y'
        ELSE 'AUTO'
    END IN ( 'AUTO','Y'  );

select * from table(dbms_xplan.display);



Plan hash value: 1579167612

-------------------------------------------------------------------------------------------------
| Id  | Operation         | Name                        | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                             | 10000 | 50000 |     5   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| RSE_CD_D_PRODUCT_BRANCH_CUR | 10000 | 50000 |     5   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(CASE "BASE_STOCK_FLAG" WHEN '0' THEN 'N' WHEN '1' THEN 'Y' ELSE 'AUTO' END 
              ='AUTO' OR CASE "BASE_STOCK_FLAG" WHEN '0' THEN 'N' WHEN '1' THEN 'Y' ELSE 'AUTO' END 
              ='Y')

在您的环境中应用它。

您可能需要对表达式进行调整才能使其恰到好处。我不确定 Oracle 如何将表达式与真正的谓词进行匹配。可能需要将架构名称添加到表达式中。

【讨论】:

  • 我没有权限获取数据库的统计信息。尽管对于计划 ID 13 的行,正如您所说,它显示的是“按索引 ROWID 访问表”。我在 db 上检查了 'BASE_STOCK_FLAG' 上没有索引,那么它指的是什么索引。然后我运行上面的查询,它显示了完整的表访问,为什么它不使用索引?
  • 计划 ID 14 使用 FULL_ISO 谓词访问索引 RSE_CD_D_PROD_BRANC_CUR_I2。该操作返回一组 ROWID。然后可以使用这些 ROWID 快速访问计划 ID 13 中的表。计划 ID 13 还根据 CASE 谓词过滤行。这有点令人困惑,因为 Plan ID 13 做了两件事 - 基于 ROWID 隐式索引的访问,然后基于 CASE 进行过滤。在我的简单示例中,只有全表扫描,因为没有其他步骤或对象。但是对基数的改变应该是一样的。 (续...)
  • 我的想法不会提高计划 ID 14 和 13 的性能,但可能会提高计划其他部分的性能。这就是为什么使用 SQL 监控来发现缓慢的操作很重要的原因,否则我们都只是猜测。要调整您需要访问数据库的任何语句,您的 DBA 应该了解这一点。
  • 我尝试在所有低基数字段上应用索引,但仍然没有使用这些索引。未使用索引的原因可能是什么?以及如何确保使用索引?
【解决方案2】:

将主查询提取为子查询,然后加入附加表:

(SELECT
  SUM(val.ON_HAND_QTY) sum_on_hand_qty,
  SUM(val.COMMITTED_QTY) sum_commited_qty,
  SUM(val.COMMITTED_QTY_RAW) sum_commited_qty_raw,
  SUM(val.DEMAND_PER_DAY_ECL_HUB) sum_demand_per_day_ecl_hub,
  SUM(val.INBOUND_RECEIPT_QTY) sum_inbound_receipt_qty,
  val.BRANCH_STOCK_FLAG,
  val.DW_BRANCH_ID,
  val.PRODUCT_ID
FROM RSE.RSE_IV_F_VALUATION_SV val
JOIN RSE.RSE_CD_D_CALENDAR cal ON cal.CALENDAR_DATE=val.VALUATION_DATE AND cal.DAY_RELATIVE  =  0
WHERE val.SSO_ID= '570000018' AND val.LOCATION_TYPE_DESC  IN  ( 'CONSIGNMENT','STOCK','PREVIEW QUEUE','TAGGED'  )
GROUP BY val.DW_BRANCH_ID,val.PRODUCT_ID,val.BRANCH_STOCK_FLAG
HAVING SUM(val.DEMAND_PER_DAY_ECL_HUB)>0) sums

【讨论】:

    【解决方案3】:

    如您所述,执行查询所需的估计时间实际时间存在显着差异。解释计划中显示的估计时间是01:35:59,但是您提到实际花费的时间是4到5个小时。这可能是由于统计数据已过时。

    收集所有对象的统计数据,并检查解释计划。您可以在架构级别执行此操作:

    EXEC DBMS_STATS.gather_schema_stats('SCHEMA_NAME');
    

    没有全表扫描,但是RSE_CD_D_PROD_BRANC_CUR_I2 上的索引范围扫描 正在估计208k 行。所以,根据表的总行数,你需要决定一个索引是否真的有用。请记住,索引并不总是有用的,全表扫描并不总是不好的

    文档说,

    如果您经常要检索大表中少于 15% 的行,请创建索引。

    但是,在实际使用中,不到 15%。因此,假设您从表中选择超过 ~20% 的行,全表扫描比索引扫描好得多。此外,正如我已经说过的,收集最新的统计信息将有助于优化器确定最佳的执行计划。

    简而言之,就是基数

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-13
      • 1970-01-01
      • 2021-05-09
      • 2021-09-28
      相关资源
      最近更新 更多