【问题标题】:Oracle SQL query taking too long like 60 minutes to executeOracle SQL 查询执行时间过长,例如 60 分钟
【发布时间】:2014-10-09 07:54:53
【问题描述】:

我有一个查询耗时过长,即 60 分钟。我是程序员,但我不太确定所有表是否都是索引。

这里是查询,任何以_V结尾的表都是视图:

SELECT prod_eff.facility
     , prod_eff.product
     , (SELECT MIN (cbv1.bucket_header) 
          FROM AMD_OARS.CURRENT_BUCKETS_V cbv1
         WHERE cbv1.version_id  = 1
           AND cbv1.min_datetime >= prod_eff.EFF_START_DATETIME
       ) min_eff
     , (SELECT MAX (cbv1.bucket_header)
          FROM AMD_OARS.CURRENT_BUCKETS_V cbv1
         WHERE cbv1.version_id = 1
           AND cbv1.min_datetime < prod_eff.EFF_END_DATETIME
       ) max_eff
     , 1 valid
  FROM (
        SELECT pf.product
             , pf.facility
             , pf.eff_start_datetime
             , pf.eff_end_datetime
          FROM AMD_OARS.BOM_PRODUCT_FACILITY pf
             , AMD_OARS.MASTER_FACILITY f
         WHERE pf.version_id = 114847
           AND pf.facility     = f.facility
           AND f.facility     != 'NONE'
           AND f.validated     = 1
       ) prod_eff
     , AMD_OARS.TEMP_SELECTED_PRODUCT tsp
 WHERE tsp.product = prod_eff.product
   AND (prod_eff.EFF_START_DATETIME BETWEEN 
            to_timestamp('07/27/2014 00:00:01.000', 'mm/dd/yyyy hh24:mi:ss.ff3') AND 
            to_timestamp('12/20/2015 00:00:00.000', 'mm/dd/yyyy  hh24:mi:ss.ff3') OR 
        prod_eff.EFF_END_DATETIME BETWEEN 
            to_timestamp('07/27/2014 00:00:01.000', 'mm/dd/yyyy hh24:mi:ss.ff3') AND 
            to_timestamp('12/20/2015 00:00:00.000', 'mm/dd/yyyy hh24:mi:ss.ff3') 
       )
 ORDER BY 1, 2, 3, 4 ;

这是我用来确定某些表是否为索引的查询。

select table_name 
from dba_tables 
where (owner, table_name) not in (select table_owner, table_name from dba_indexes)
and table_name = 'TEMP_SELECTED_PRODUCT';

对不起,我是数据库方面的新手。我只知道 sql join 和编写基本查询之类的基本知识。任何帮助将不胜感激。我正在使用 Oracle SQL Developer。

如果我做错了什么,有人可以指导我吗?我会很感激。

更新: 我看到this video 了解如何执行“解释计划”,这就是我得到的结果

Plan hash value: 1792060973

-------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name                 | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                      |     1 |    78 |     4  (25)| 00:00:01 |
|   1 |  SORT AGGREGATE                |                      |     1 |    66 |            |          |
|*  2 |   TABLE ACCESS BY INDEX ROWID  | TEMP_CURRENT_BUCKETS |     1 |    66 |     1   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN            | TCB_PK               |     1 |       |     1   (0)| 00:00:01 |
|   4 |  SORT AGGREGATE                |                      |     1 |    66 |            |          |
|*  5 |   TABLE ACCESS BY INDEX ROWID  | TEMP_CURRENT_BUCKETS |     1 |    66 |     1   (0)| 00:00:01 |
|*  6 |    INDEX RANGE SCAN            | TCB_PK               |     1 |       |     1   (0)| 00:00:01 |
|   7 |  SORT ORDER BY                 |                      |     1 |    78 |     4  (25)| 00:00:01 |
|   8 |   NESTED LOOPS                 |                      |     1 |    78 |     3   (0)| 00:00:01 |
|   9 |    NESTED LOOPS                |                      |     1 |    69 |     2   (0)| 00:00:01 |
|  10 |     INDEX FULL SCAN            | TSP_PK               |     1 |    18 |     1   (0)| 00:00:01 |
|* 11 |     TABLE ACCESS BY INDEX ROWID| BOM_PRODUCT_FACILITY |     1 |    51 |     1   (0)| 00:00:01 |
|* 12 |      INDEX RANGE SCAN          | BPF_PK               |     1 |       |     1   (0)| 00:00:01 |
|* 13 |    TABLE ACCESS BY INDEX ROWID | MASTER_FACILITY      |     1 |     9 |     1   (0)| 00:00:01 |
|* 14 |     INDEX UNIQUE SCAN          | MF_F_PK              |     1 |       |     1   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------

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

   2 - filter("CB"."MIN_DATETIME">=:B1)
   3 - access("CB"."VERSION_ID"=1)
   5 - filter("CB"."MIN_DATETIME"<:B1)
   6 - access("CB"."VERSION_ID"=1)
  11 - filter(INTERNAL_FUNCTION("PF"."EFF_START_DATETIME")>=TIMESTAMP' 2014-07-27 
              00:00:01.000000000' AND INTERNAL_FUNCTION("PF"."EFF_START_DATETIME")<=TIMESTAMP' 2015-12-20 
              00:00:00.000000000' OR INTERNAL_FUNCTION("PF"."EFF_END_DATETIME")>=TIMESTAMP' 2014-07-27 
              00:00:01.000000000' AND INTERNAL_FUNCTION("PF"."EFF_END_DATETIME")<=TIMESTAMP' 2015-12-20 
              00:00:00.000000000')
  12 - access("PF"."VERSION_ID"=114847 AND "TSP"."PRODUCT"="PF"."PRODUCT")
       filter("TSP"."PRODUCT"="PF"."PRODUCT" AND "PF"."FACILITY"<>'NONE')
  13 - filter("F"."VALIDATED"=1)
  14 - access("PF"."FACILITY"="F"."FACILITY")
       filter("F"."FACILITY"<>'NONE')

【问题讨论】:

  • 向我们展示执行计划。
  • 我不知道你是什么意思?我浏览了视图内的每个查询并检查它是否被索引?但我很困惑 dba_indexes 和 user_indexes 之间有什么区别
  • 索引不会神奇地提高应用程序的性能,如果没有索引的方式更快,Oracle 不会使用它。首先你要收集statistics,其次生成一个explain plan,最后,show是解释计划
  • @Jiten 您可以在此处了解 11g 的解释计划以及如何执行这些计划,docs.oracle.com/cd/E11882_01/server.112/e41573/…
  • @JitenK 你收集统计数据了吗?我看不出有什么会损害你的表现

标签: sql oracle oracle11g indexing oracle-sqldeveloper


【解决方案1】:
SELECT prod_eff.facility
     , prod_eff.product
     , (SELECT MIN (cbv1.bucket_header) 
          FROM AMD_OARS.CURRENT_BUCKETS_V cbv1
         WHERE cbv1.version_id  = 1
           AND cbv1.min_datetime >= prod_eff.EFF_START_DATETIME
       ) min_eff
     , (SELECT MAX (cbv1.bucket_header)
          FROM AMD_OARS.CURRENT_BUCKETS_V cbv1
         WHERE cbv1.version_id = 1
           AND cbv1.min_datetime < prod_eff.EFF_END_DATETIME
       ) max_eff
     , 1 valid
  FROM (
        WITH prod_fac AS (
            SELECT pf.product
                 , pf.facility
                 , pf.eff_start_datetime
                 , pf.eff_end_datetime
              FROM AMD_OARS.BOM_PRODUCT_FACILITY pf
             WHERE pf.version_id = 114847
               AND (pf.EFF_START_DATETIME BETWEEN 
                       to_timestamp('07/27/2014 00:00:01.000',
                                    'mm/dd/yyyy hh24:mi:ss.ff3') AND 
                       to_timestamp('12/20/2015 00:00:00.000',
                                    'mm/dd/yyyy  hh24:mi:ss.ff3') OR 
                    pf.EFF_END_DATETIME BETWEEN 
                       to_timestamp('07/27/2014 00:00:01.000',
                                    'mm/dd/yyyy hh24:mi:ss.ff3') AND 
                       to_timestamp('12/20/2015 00:00:00.000',
                                    'mm/dd/yyyy hh24:mi:ss.ff3') 
                   )
        )
        SELECT pf2.product
             , pf2.facility
             , pf2.eff_start_datetime
             , pf2.eff_end_datetime
          FROM prod_fac pf2, AMD_OARS.MASTER_FACILITY f
           AND pf2.facility = f.facility
           AND f.facility  != 'NONE'
           AND f.validated = 1
       ) prod_eff, AMD_OARS.TEMP_SELECTED_PRODUCT tsp
  WHERE prod_eff.product = tsp.product
 ORDER BY 1, 2, 3, 4 ;
  • 在最终加入您的 tsp 表之前,我会尝试尽可能多地删除数据。日期范围检查移至内联视图。
  • 我不喜欢您如何在 from 类和 where 子句中的顺序之间翻转表顺序。 tsp.product = prod_eff.product = > prod_eff.product = tsp.product
  • 我喜欢你在 to_timestamp 函数中使用 between 子句的方式。许多人尝试trunc() 的时间,这会破坏索引的使用。
  • 如果您能以某种方式删除两个标量查询中的 >= 和

【讨论】:

    【解决方案2】:

    在检查您的查询期间,我遇到了这个

    AND (prod_eff.EFF_START_DATETIME BETWEEN 
            to_timestamp('07/27/2014 00:00:01.000', 'mm/dd/yyyy hh24:mi:ss.ff3') AND 
            to_timestamp('12/20/2015 00:00:00.000', 'mm/dd/yyyy  hh24:mi:ss.ff3') OR 
        prod_eff.EFF_END_DATETIME BETWEEN 
            to_timestamp('07/27/2014 00:00:01.000', 'mm/dd/yyyy hh24:mi:ss.ff3') AND 
            to_timestamp('12/20/2015 00:00:00.000', 'mm/dd/yyyy hh24:mi:ss.ff3') 
       )
    

    我认为它们是相同的,我想这部分对您的查询性能的损害最大,去掉其中一个,像这样重写您的查询:

    SELECT prod_eff.facility
         , prod_eff.product
         , (SELECT MIN (cbv1.bucket_header) 
              FROM AMD_OARS.CURRENT_BUCKETS_V cbv1
             WHERE cbv1.version_id  = 1
               AND cbv1.min_datetime >= prod_eff.EFF_START_DATETIME
           ) min_eff
         , (SELECT MAX (cbv1.bucket_header)
              FROM AMD_OARS.CURRENT_BUCKETS_V cbv1
             WHERE cbv1.version_id = 1
               AND cbv1.min_datetime < prod_eff.EFF_END_DATETIME
           ) max_eff
         , 1 valid
      FROM (
            SELECT pf.product
                 , pf.facility
                 , pf.eff_start_datetime
                 , pf.eff_end_datetime
              FROM AMD_OARS.BOM_PRODUCT_FACILITY pf
                 , AMD_OARS.MASTER_FACILITY f
             WHERE pf.version_id = 114847
               AND pf.facility     = f.facility
               AND f.facility     != 'NONE'
               AND f.validated     = 1
           ) prod_eff
         , AMD_OARS.TEMP_SELECTED_PRODUCT tsp
     WHERE tsp.product = prod_eff.product
       AND prod_eff.EFF_START_DATETIME BETWEEN 
                to_timestamp('07/27/2014 00:00:01.000', 'mm/dd/yyyy hh24:mi:ss.ff3') AND 
                to_timestamp('12/20/2015 00:00:00.000', 'mm/dd/yyyy  hh24:mi:ss.ff3')
     ORDER BY 1, 2, 3, 4 ;
    

    【讨论】:

    • 你认为它们是如何以及为什么相同的?这个字段也需要验证 --> prod_eff.EFF_END_DATETIME BETWEEN
    • 我发现 'EFF_START_DATETIME' 和 'EFF_END_DATETIME' 没有被索引,如何将这些列添加到索引中?
    • 对不起,我没有看到你使用不同的列,你是对的他们不一样
    猜你喜欢
    • 2013-09-16
    • 1970-01-01
    • 1970-01-01
    • 2019-04-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多