SQL脚本运行非常缓慢,只需稍加改动

时间:2016-11-24 17:30:26

标签: sql oracle

我对SQL比较陌生。我有一个过去非常快速运行的脚本(<0.5秒),但如果我添加一个更改,则运行速度非常慢(> 120秒) - 我无法理解为什么这种变化会产生如此大的影响。任何帮助都将非常感激!

这是脚本,如果我不包含“tt2.bulk_cnt,它会快速运行 “第26行:

with bulksum1 as
(
select  t1.membercode,
        t1.schemecode,
        t1.transdate
from mina_raw2 t1
where t1.transactiontype in ('RSP','SP','UNTV','ASTR','CN','TVIN','UCON','TRAS')
group by  t1.membercode,
          t1.schemecode,
          t1.transdate
),

bulksum2 as
(
select  t1.schemecode,
        t1.transdate,
        count(*) as bulk_cnt
from bulksum1 t1
group by  t1.schemecode,
          t1.transdate
having count(*) >= 10
),

results as
(
select t1.*, tt2.bulk_cnt
from mina_raw2 t1
inner join bulksum2 tt2
on t1.schemecode = tt2.schemecode and t1.transdate = tt2.transdate
where t1.transactiontype in ('RSP','SP','UNTV','ASTR','CN','TVIN','UCON','TRAS')
)

select * from results
编辑:我为之前没有提供足够的细节而道歉 - 尽管我可以使用基本的SQL代码,但对于数据库来说,我是一个完整的新手。

数据库:Oracle(我不确定是哪个版本,对不起)

执行计划:

快速查询:

Plan hash value: 1712123489

---------------------------------------------
| Id  | Operation               | Name      |
---------------------------------------------
|   0 | SELECT STATEMENT        |           |
|   1 |  HASH JOIN              |           |
|   2 |   VIEW                  |           |
|   3 |    FILTER               |           |
|   4 |     HASH GROUP BY       |           |
|   5 |      VIEW               | VM_NWVW_0 |
|   6 |       HASH GROUP BY     |           |
|   7 |        TABLE ACCESS FULL| MINA_RAW2 |
|   8 |   TABLE ACCESS FULL     | MINA_RAW2 |
---------------------------------------------

慢速查询:

Plan hash value: 1298175315

--------------------------------------------
| Id  | Operation              | Name      |
--------------------------------------------
|   0 | SELECT STATEMENT       |           |
|   1 |  FILTER                |           |
|   2 |   HASH GROUP BY        |           |
|   3 |    HASH JOIN           |           |
|   4 |     VIEW               | VM_NWVW_0 |
|   5 |      HASH GROUP BY     |           |
|   6 |       TABLE ACCESS FULL| MINA_RAW2 |
|   7 |     TABLE ACCESS FULL  | MINA_RAW2 |
--------------------------------------------

2 个答案:

答案 0 :(得分:0)

我设法删除了一个不必要的子查询,但distinctcount的这种语法在PostgreSQL之外可能不起作用,或者可能不是所需的结果。我知道我当然在那里使用它。

select t1.*, tt2.bulk_cnt
from mina_raw2 t1
inner join (select  t2.schemecode,
        t2.transdate,
        count(DISTINCT membercode) as bulk_cnt
from mina_raw2 t2
where t2.transactiontype in ('RSP','SP','UNTV','ASTR','CN','TVIN','UCON','TRAS')
group by  t2.schemecode,
          t2.transdate
having count(DISTINCT membercode) >= 10) tt2
on t1.schemecode = tt2.schemecode and t1.transdate = tt2.transdate
where t1.transactiontype in ('RSP','SP','UNTV','ASTR','CN','TVIN','UCON','TRAS')

当您使用这些with查询时,而不是在您不需要时查询子查询时,您可以将查询优化程序放在膝盖上。

答案 1 :(得分:0)

一些观察,然后做一些事情:

1)需要更多信息。特别是,MINA_RAW2表中有多少行,此表中存在哪些索引,以及最后一次分析时是什么时候?要确定这些问题的答案,请运行:

SELECT COUNT(*) FROM MINA_RAW2;

SELECT TABLE_NAME, LAST_ANALYZED, NUM_ROWS
  FROM USER_TABLES
  WHERE TABLE_NAME = 'MINA_RAW2';

从查看计划输出看起来数据库在MINA_RAW2上进行了两次全面扫描 - 如果可以将其减少到不超过一个,那将会很好,希望没有。如果没有关于表中数据的非常详细的信息,总是很难说,但乍一看似乎TRANSACTIONTYPE上的索引可能会有所帮助。如果这样的索引不存在,您可能需要考虑添加它。

2)假设统计数据已过时(自上次分析以来,已添加,删除或更新了旧的,不存在或大量数据(> 10%))运行以下内容:

BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(owner => 'YOUR-SCHEMA-NAME',
                                table_name => 'MINA_RAW2');
END;

将上面的“YOUR-SCHEMA-NAME”替换为正确的架构名称。请记住将架构名称大写!如果您不知道您是否应该收集统计数据,请谨慎行事并做到这一点。它不应该花费太多时间。

3)更新表统计信息后重新尝试现有查询。我认为在数据库中拥有最新统计数据可以解决您的问题。如果不是:

4)此查询正在对GROUP BY的结果执行GROUP BY。这似乎没有必要,因为初始GROUP BY没有进行任何分组 - 相反,似乎这样做是为了获得MEMBERCODE,SCHEMECODE和TRANSDATE的唯一组合,以便按计划和日期可以确定。我认为整个查询可以简化为:

WITH cteWORKING_TRANS AS (SELECT *
                            FROM MINA_RAW2
                            WHERE TRANSACTIONTYPE IN ('RSP','SP','UNTV',
                                                      'ASTR','CN','TVIN',
                                                      'UCON','TRAS')),
     cteBULKSUM AS (SELECT a.SCHEMECODE,
                           a.TRANSDATE,
                           COUNT(*) AS BULK_CNT
                      FROM (SELECT DISTINCT MEMBERCODE,
                                            SCHEMECODE,
                                            TRANSDATE
                              FROM cteWORKING_TRANS) a
                      GROUP BY a.SCHEMECODE,
                               a.TRANSDATE)
SELECT t.*, b.BULK_CNT
  FROM cteWORKING_TRANS t
  INNER JOIN cteBULKSUM b
    ON b.SCHEMECODE = t.SCHEMECODE AND
       b.TRANSDATE = t.TRANSDATE