0
select round(avg(et_gsm_sınyal)) as sinyal,mahalle_kodu,ilce_kodu,sebeke 
from 
    (select et_gsm_sınyal,sozlesme_no,SUBSTR(et_operator,1,5) as sebeke 
    from thkol316old 
    where tarih >= ADD_MONTHS (TRUNC (SYSDATE, 'MM'), -1) 
    AND tarih < TRUNC(SYSDATE, 'MM')) okuma, 
    (select sozlesme_no,ilce_kodu,mahalle_kodu from commt020) bilgiler 
where okuma.sozlesme_no=bilgiler.sozlesme_no  
group by mahalle_kodu,ilce_kodu,sebeke;
  • commt020 -> 客户表
  • thkol316old -> 旧账单表

此查询有效,但运行速度非常慢。

响应时间约为 550 秒。

我应该怎么做这个查询更快?

这是执行计划

SELECT STATEMENT 7547          

 HASH 
     GROUP BY    7547          

 FILTER 


 Filter Predicates 

 ADD_MONTHS(TRUNC(SYSDATE@!,'fmmm'),-1)

 NESTED LOOPS 


 NESTED LOOPS 
         7546          

 TABLE ACCESS 
 COMMT020    BY GLOBAL INDEX ROWID   3   ROW LOCATION    ROW LOCATION`
4

3 回答 3

0

首先,您不需要 BILIGILER 内联视图来从 COMMT020 表中选择几列,直接从该表中选择就可以了:

SELECT ROUND(AVG(et_gsm_s1nyal)) AS sinyal,
      mahalle_kodu,ilce_kodu,sebeke
FROM (
    SELECT et_gsm_s1nyal,
          sozlesme_no,
          SUBSTR(et_operator,1,5) AS sebeke
    FROM thkol316old
    WHERE tarih >= ADD_MONTHS (TRUNC (SYSDATE, 'MM'), -1)
    AND   tarih < TRUNC(SYSDATE, 'MM')
    ) okuma, commt020    
WHERE okuma.sozlesme_no = commt020.sozlesme_no
GROUP BY mahalle_kodu,ilce_kodu,sebeke
/

然后,让我们使用 ANSI 连接表达式重写连接。我更喜欢 ANSI 连接而不是旧的 Oracle 样式连接,因为它们允许将连接条件与过滤条件分开,因此可以更清楚地了解实际发生的情况。此外,为表格分配别名并清楚地指示我们从哪个表格中选择哪些列是一种很好的风格。

SELECT ROUND(AVG(o.et_gsm_s1nyal)) AS sinyal,
      c.mahalle_kodu, c.ilce_kodu, o.sebeke
FROM (
    SELECT th.et_gsm_s1nyal,
          th.sozlesme_no,
          SUBSTR(th.et_operator,1,5) AS sebeke
    FROM thkol316old th
    WHERE th.tarih >= ADD_MONTHS (TRUNC (SYSDATE, 'MM'), -1)
    AND   th.tarih < TRUNC(SYSDATE, 'MM')
    ) okuma o
JOIN  commt020 c ON o.sozlesme_no = c.sozlesme_no   
GROUP BY c.mahalle_kodu, c.ilce_kodu, o.sebeke
/

现在它比剩余的内联视图也更清楚了。虽然如果不知道这些表的详细信息就很难判断,但您最好“解开”该内联视图并用直接连接替换它:

SELECT ROUND(AVG(th.et_gsm_s1nyal)) AS sinyal,
       c.mahalle_kodu,
       c.ilce_kodu,
       SUBSTR(th.et_operator,1,5) AS sebeke
FROM  commt020 c
JOIN  thkol316old th ON c.sozlesme_no = th.sozlesme_no
WHERE th.tarih >= ADD_MONTHS (TRUNC (SYSDATE, 'MM'), -1)
AND   th.tarih < TRUNC(SYSDATE, 'MM')
GROUP BY c.mahalle_kodu, c.ilce_kodu, SUBSTR(th.et_operator,1,5)
/

不幸的是,优化此查询还需要其他信息,例如:

  • 新的执行计划。
  • 您正在使用的 Oracle 版本。
  • THKOL316OLD 和 COMMT020 表中的行数。
  • 这些表上存在哪些索引。
于 2013-08-25T23:42:27.173 回答
0

首先,我会尝试使用普通的表连接而不是更尴尬的内联视图 - 连接,我希望以下方法可以工作(我还没有创建表并尝试过):

select round(avg(okuma.et_gsm_sınyal)) as sinyal,
bilgiler.mahalle_kodu,bilgiler.ilce_kodu, SUBSTR(okuma.et_operator,1,5) as sebeke 
from thkol316old okuma
inner join commt020 bilgiler on okuma.sozlesme_no=bilgiler.sozlesme_no
where okuma.tarih >= ADD_MONTHS (TRUNC (SYSDATE, 'MM'), -1) 
AND okuma.tarih < TRUNC(SYSDATE, 'MM')
group by bilgiler.mahalle_kodu,bilgiler.ilce_kodu, SUBSTR(okuma.et_operator,1,5);

然后,如果事情仍然很慢:

  1. 验证是否存在 bilgiler.sozlesme_no 是索引中第一列的索引
  2. 验证是否存在 okuma.sozlesme_no 是索引中第一列的索引
  3. 验证是否存在 okuma.tarih 是索引中第一列的索引
于 2013-08-15T14:26:53.227 回答
0

清楚地

列 tarih 未为表 thkol316old 编制索引

create index tarih_idx on thkol316old (tarih);

然后

analyze table commt020 compute statistics;
analyze table thkol316old compute statistics;

在 Oracle 中,分析表会生成用于创建查询执行计划的信息。每次更改表时,您可能还想分析它。许多大型系统都按计划进行。

于 2013-08-15T15:26:59.893 回答