2010-12-02 61 views
0

我有一个查询其需要5巨额表数据,可以请你帮我这个查询的性能优化:帮助SQL调优 - ORACLE

SELECT DECODE(SIGN((t1.amount - NVL(t2.amount, 0)) - 4.999), 1, NVL(t2.amount, 0), t1.amount) AS amount_1, 
     t1.element_id, 
     t1.start_date , 
     t1.amount, 
     NVL(t5.abrev, NULL) AS criteria, 
     t1.case_id , 
     NVL(t5.value, NULL) segment, 
     add_months(t1.start_date, -1) invoice_date, 
     NVL((SELECT SUM(b.amount) 
      FROM TABLE1 a, TABLE3 b 
      WHERE a.element_id = b.element_id 
       AND b.date_invoicing < a.start_date 
       AND t1.element_id = a.element_id), 
      0) amount_2 
    FROM TABLE1 t1, TABLE2 t2, TABLE3 t3, TABLE4 t4, TABLE5 t5 
WHERE t1.TYPE = 'INVOICE' 
    AND t2.case_id = t3.case_id 
    AND t2.invoicing_id = t3.invoicing_id 
    AND t2.date_unpaid IS NULL 
    AND t1.element_id = t3.element_id(+) 
    AND add_months(t1.start_date, -1) < 
     NVL(t4.DT_FIN_DT(+), SYSDATE) 
    AND add_months(t1.start_date, -1) >= t4.date_creation(+) 
    AND t1.case_id = t4.case_id(+) 
    AND t4.segment = t5.abrev(+) 
    AND t5.Type(+) = 'CRITERIA_TYPE'; 

是有什么错误的,可以用什么来代替其他?
感谢您的帮助

+2

现在你已经尝试使用(+)外连接到t3,通过其他不使用(+)的谓词强制回到内连接,如“t2.case_id = t3.case_id”。如果你可以使用ANSI连接编写它,它将不太容易出错并且易于阅读。尽管如此,这与性能无关。 – 2010-12-02 14:16:25

回答

1

正如其他人所指出的,很难说不看执行计划。

但是......有些事情我会与有关:如@TonyAndrews在他的评论中提及了上述

  1. 的外连接表3在主查询是不完整的。请参阅Common errors seen when using OUTER-JOIN上的“不完整联结跟踪”示例。 这意味着您的查询可能产生了错误的结果,但是如果不知道查询和模式的完整意图,除了您可以确定地知道这一点外,没有人会这样做。

    更新您的查询以使用Oracle风格TableName.ColumnName(+)中的ANSI风格INNER/[LEFT|RIGHT] OUTER语法将有助于使这一点更加明显。

  2. 标量子查询将得到运行的每一行,可能会很慢(假设TABLE3很大)。

    NVL((SELECT SUM(b.amount) 
        FROM TABLE1 a, TABLE3 b 
        WHERE a.element_id = b.element_id 
         AND b.date_invoicing < a.start_date 
         AND t1.element_id = a.element_id), 
        0) amount_2 
    

    因此,我没有看到有必要在这个子查询又包括表1:如果有不TABLE3.element_idTABLE3.date_invoicing有用的索引这将是极其缓慢。这可能是更好的重构为这样:

    NVL((SELECT SUM(b.amount) 
        FROM TABLE3 b 
        WHERE t1.element_id = b.element_id 
         AND b.date_invoicing < t1.start_date, 
        0) amount_2 
    

    或者,你甚至可能会更好重构这个使用分析功能(SO questionOracle documentation)如果为b.amount值相加的标准是相同的,包括他们在查询摆在首位:

    SUM(b.amount) OVER (PARTITION BY b.element_id) amount_2 
    

    显然,你现在有不同的标准来总结b.amount,因为你在主要查询和子查询中以不同的方式加入到TABLE3中,但我想象这更像是“不完整的加入路径”的一个因素,而不是有目的的设计(我的猜测,因为我不能从代码本身讲出查询的意图)。

2

您必须做的第一件事是使用显式联接。这会将您的连接与您的过滤器分开,并帮助您更好地调整此过滤器。

请检查这些连接是否正确。

SELECT 
    DECODE(SIGN((t1.amount - NVL(t2.amount, 0)) - 4.999), 1, NVL(t2.amount, 0), t1.amount) AS amount_1, 
    t1.element_id, 
    t1.start_date , 
    t1.amount, 
    NVL(t5.abrev, NULL) AS criteria, 
    t1.case_id , 
    NVL(t5.value, NULL) segment, 
    add_months(t1.start_date, -1) invoice_date, 
    NVL 
    (
     (SELECT SUM(b.amount) 
     FROM TABLE1 a, TABLE3 b 
     WHERE a.element_id = b.element_id 
     AND b.date_invoicing < a.start_date 
     AND t1.element_id = a.element_id), 
    0) amount_2 
FROM 
    TABLE1 t1 

    LEFT OUTER JOIN TABLE3 t3 
     on t1.element_id = t3.element_id 

    INNER JOIN TABLE2 t2, 
     on t2.invoicing_id = t3.invoicing_id 
     and t2.case_id = t3.case_id 

    LEFT OUTER JOIN TABLE4 t4 
     on t1.case_id = t4.case_id 

    LEFT OUTER JOIN TABLE5 t5 
     on t4.segment = t5.abrev 

WHERE t1.TYPE = 'INVOICE' 
    AND t2.date_unpaid IS NULL 
    AND add_months(t1.start_date, -1) < NVL(t4.DT_FIN_DT(+), SYSDATE) 
    AND add_months(t1.start_date, -1) >= t4.date_creation(+) 
    AND t5.Type(+) = 'CRITERIA_TYPE'; 

如果是,那么你可以做几件事情,但最好的办法是看执行计划。

+0

它会提高性能还是提高可读性? – mcha 2010-12-02 14:14:50

+2

在性能方面,它们应该完全一样。分离可以帮助您识别要调整得更好的东西。 – 2010-12-02 14:22:27

1

优化程序可能产生了不理想的执行计划。或者考虑到数据库实际需要完成的工作量,它可能会尽可能快地运行。 没有解释计划,知道键,关系和索引,有点难以分辨发生了什么。

选择列表中的标量子查询是通常当外部查询返回大量行时,不是一个好主意。

由于函数调用,以下表达式可能会阻止优化器使用统计信息。索引可能不会用于出于同样的原因。

AND add_months(t1.start_date, -1) < NVL(t4.DT_FIN_DT(+), SYSDATE) 
AND add_months(t1.start_date, -1) >= t4.date_creation(+) 

真的不能比这更具体的:)

0

这是升技奇怪在这里,当你窝Select语句内的另一个

NVL((SELECT SUM(b.amount) 
      FROM TABLE1 a, TABLE3 b 
      WHERE a.element_id = b.element_id 
       AND b.date_invoicing < a.start_date 
       AND t1.element_id = a.element_id), 
      0) amount_2 

你需要为表写一遍后“从”加入。