如何优化在Oracle数据库上运行的SELECT语句?

时间:2012-04-13 03:55:57

标签: sql oracle

我在ORACLE中有一个SELECT语句:

SELECT COUNT(DISTINCT ds1.endpoint_msisdn)                  multiple30,
       dss1.service,
       dss1.endpoint_provisioning_id,
       dss1.company_scope,
       Nvl(x.subscription_status, dss1.subscription_status) subscription_status
FROM   daily_summary ds1
       join daily_summary ds2
         ON ds1.endpoint_msisdn = ds2.endpoint_msisdn,
       daily_summary_static dss1,
       daily_summary_static dss2,
       (SELECT NULL subscription_status
        FROM   dual
        UNION ALL
        SELECT -2 subscription_status
        FROM   dual) x
WHERE  ds1.summary_ts >= To_date('10-04-2012', 'dd-mm-yyyy') - 30
       AND ds1.summary_ts <= To_date('10-04-2012', 'dd-mm-yyyy')
       AND dss1.last_active >= To_date('10-04-2012', 'dd-mm-yyyy') - 30
       AND dss1.last_active <= To_date('10-04-2012', 'dd-mm-yyyy')
       AND dss2.last_active >= To_date('10-04-2012', 'dd-mm-yyyy') - 30
       AND dss2.last_active <= To_date('10-04-2012', 'dd-mm-yyyy')
       AND dss1.service <> dss2.service
       AND ( dss1.company_scope = 2
              OR dss1.company_scope = 5 )
       AND ( dss2.company_scope = 2
              OR dss2.company_scope = 5 )
       AND dss1.company_scope = dss2.company_scope
       AND ds1.endpoint_noc_id = dss1.endpoint_noc_id
       AND ds1.endpoint_host_id = dss1.endpoint_host_id
       AND ds1.endpoint_instance_id = dss1.endpoint_instance_id
       AND ds2.endpoint_noc_id = dss2.endpoint_noc_id
       AND ds2.endpoint_host_id = dss2.endpoint_host_id
       AND ds2.endpoint_instance_id = dss2.endpoint_instance_id
       AND dss1.endpoint_provisioning_id = dss2.endpoint_provisioning_id
       AND Least(1, ds1.total_actions) = 1
       AND Least(1, ds2.total_actions) = 1
GROUP  BY dss1.service,
          dss1.endpoint_provisioning_id,
          dss1.company_scope,
          Nvl(x.subscription_status, dss1.subscription_status); 

此查询在我的环境中返回大约需要26分钟,但如果我删除该部分:

dss1.last_active >= to_date('10-04-2012','dd-mm-yyyy') - 30 AND
                   dss1.last_active <= to_date('10-04-2012','dd-mm-yyyy') AND
                    dss2.last_active >= to_date('10-04-2012','dd-mm-yyyy') - 30 AND
                   dss2.last_active <= to_date('10-04-2012','dd-mm-yyyy') AND

只需要20秒就能运行。

我们在last_active列上有索引,我不知道为什么这个部分的性能如此之慢?有任何想法吗?


如果我这样做,那就非常快。

select * from daily_summary_static where last_active >= to_date('10-04-2012','dd-mm-yyyy') - 30 AND last_active <= to_date('10-04-2012','dd-mm-yyyy');


解释声明的计划,我在这里看不到任何全表扫描,不知道为什么它运行得这么慢:

----------------------------------------------------------------------------------------------------------------
| Id  | Operation                               | Name                 | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                        |                      |     1 |   119 |   204   (3)| 00:00:03 |
|   1 |  SORT GROUP BY                          |                      |     1 |   119 |   204   (3)| 00:00:03 |
|   2 |   MERGE JOIN CARTESIAN                  |                      |     1 |   119 |   203   (2)| 00:00:03 |
|*  3 |    TABLE ACCESS BY INDEX ROWID          | DAILY_SUMMARY        |     1 |    27 |    11   (0)| 00:00:01 |
|   4 |     NESTED LOOPS                        |                      |     1 |   116 |   199   (3)| 00:00:03 |
|*  5 |      HASH JOIN                          |                      |     3 |   267 |   178   (3)| 00:00:03 |
|*  6 |       HASH JOIN                         |                      |     1 |    65 |   140   (2)| 00:00:02 |
|   7 |        TABLE ACCESS BY INDEX ROWID      | DAILY_SUMMARY_STATIC |    61 |  1647 |    37   (3)| 00:00:01 |
|   8 |         BITMAP CONVERSION TO ROWIDS     |                      |       |       |            |          |
|   9 |          BITMAP AND                     |                      |       |       |            |          |
|  10 |           BITMAP CONVERSION FROM ROWIDS |                      |       |       |            |          |
|  11 |            SORT ORDER BY                |                      |       |       |            |          |
|* 12 |             INDEX RANGE SCAN            | DSS_LAST_ACTIVE      |   560 |       |     3   (0)| 00:00:01 |
|  13 |           BITMAP OR                     |                      |       |       |            |          |
|  14 |            BITMAP CONVERSION FROM ROWIDS|                      |       |       |            |          |
|* 15 |             INDEX RANGE SCAN            | DSS_C_SCOPE_IDX      |   560 |       |    18   (0)| 00:00:01 |
|  16 |            BITMAP CONVERSION FROM ROWIDS|                      |       |       |            |          |
|* 17 |             INDEX RANGE SCAN            | DSS_C_SCOPE_IDX      |   560 |       |     1   (0)| 00:00:01 |
|  18 |        TABLE ACCESS BY INDEX ROWID      | DAILY_SUMMARY        |  1773 | 67374 |   102   (0)| 00:00:02 |
|* 19 |         INDEX RANGE SCAN                | DS_DAILY_ACTIVE_IDX  |  1767 |       |    14   (0)| 00:00:01 |
|  20 |       TABLE ACCESS BY INDEX ROWID       | DAILY_SUMMARY_STATIC |    61 |  1464 |    37   (3)| 00:00:01 |
|  21 |        BITMAP CONVERSION TO ROWIDS      |                      |       |       |            |          |
|  22 |         BITMAP AND                      |                      |       |       |            |          |
|  23 |          BITMAP CONVERSION FROM ROWIDS  |                      |       |       |            |          |
|  24 |           SORT ORDER BY                 |                      |       |       |            |          |
|* 25 |            INDEX RANGE SCAN             | DSS_LAST_ACTIVE      |   560 |       |     3   (0)| 00:00:01 |
|  26 |          BITMAP OR                      |                      |       |       |            |          |
|  27 |           BITMAP CONVERSION FROM ROWIDS |                      |       |       |            |          |
|* 28 |            INDEX RANGE SCAN             | DSS_C_SCOPE_IDX      |   560 |       |    18   (0)| 00:00:01 |
|  29 |           BITMAP CONVERSION FROM ROWIDS |                      |       |       |            |          |
|* 30 |            INDEX RANGE SCAN             | DSS_C_SCOPE_IDX      |   560 |       |     1   (0)| 00:00:01 |
|* 31 |      INDEX RANGE SCAN                   | DS_PKEY              |     8 |       |     2   (0)| 00:00:01 |
|  32 |    BUFFER SORT                          |                      |     2 |     6 |   193   (3)| 00:00:03 |
|  33 |     VIEW                                |                      |     2 |     6 |     4   (0)| 00:00:01 |
|  34 |      UNION-ALL                          |                      |       |       |            |          |
|  35 |       FAST DUAL                         |                      |     1 |       |     2   (0)| 00:00:01 |
|  36 |       FAST DUAL                         |                      |     1 |       |     2   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------------

1 个答案:

答案 0 :(得分:2)

由于此部分实际上使它变慢:

AND dss1.last_active >= To_date('10-04-2012', 'dd-mm-yyyy') - 30
AND dss1.last_active <= To_date('10-04-2012', 'dd-mm-yyyy')
AND dss2.last_active >= To_date('10-04-2012', 'dd-mm-yyyy') - 30
AND dss2.last_active <= To_date('10-04-2012', 'dd-mm-yyyy')

我觉得last_active上的索引不应该使用,即它阻止使用另一个更有用的索引。我的赌注是另一个用于加入dss1和dss2的索引,但事实上它并不重要。

因此,我建议通过故意更改块来禁用索引使用,这样查询优化器就不能再使用索引了:

AND (dss1.last_active+0) >= To_date('10-04-2012', 'dd-mm-yyyy') - 30
AND (dss1.last_active+0) <= To_date('10-04-2012', 'dd-mm-yyyy')
AND (dss2.last_active+0) >= To_date('10-04-2012', 'dd-mm-yyyy') - 30
AND (dss2.last_active+0) <= To_date('10-04-2012', 'dd-mm-yyyy')