2010-11-19 81 views
2

我有以下包含重複子查詢的巨大查詢,它對我來說看起來效率很低。我如何優化它?如何使用重複子查詢優化龐大查詢

SELECT T2.date1, T2.date2, T2.period, T1.market, T1.ticker, 0 AS scenario 
FROM 
(SELECT DISTINCT 
     Q.market AS market, 
     Q.ticker AS ticker 

FROM portfolio.scenario S RIGHT JOIN portfolio.quote Q 
ON S.series = (SELECT S.series 
        FROM scenario S 
        WHERE S.date1 >= '2009-09-01' AND 
         S.date2 <= '2010-07-01' AND 
         S.period = 'QUARTER' 
        ORDER BY S.date2 
        LIMIT 1) AND 
     Q.market = S.market AND 
     Q.ticker = S.ticker 

WHERE Q.date = '2010-07-01' AND 
     S.date1 IS NULL) AS T1 

JOIN 

(SELECT DISTINCT S.date1, S.date2, S.period 
FROM scenario S 
WHERE S.series = (SELECT S.series 
        FROM scenario S 
        WHERE S.date1 >= '2009-09-01' AND 
         S.date2 <= '2010-07-01' AND 
         S.period = 'QUARTER' 
        ORDER BY S.date2 
        LIMIT 1) AND 
     S.date1 >= '2009-09-01' AND 
     S.date2 <= '2010-07-01') AS T2 

UNION 

SELECT S.date1 AS date1, 
     S.date2 AS date2, 
     S.period AS period, 
     Q.market AS market, 
     Q.ticker AS ticker, 
     Q.close * EXP(S.ratio) AS scenario 

FROM portfolio.scenario S , portfolio.quote Q 

WHERE S.series = (SELECT S.series 
        FROM scenario S 
        WHERE S.date1 >= '2009-09-01' AND 
         S.date2 <= '2010-07-01' AND 
         S.period = 'QUARTER' 
        ORDER BY S.date2 
        LIMIT 1) AND 
     S.date1 >= '2009-09-01' AND 
     S.date2 <= '2010-07-01' AND 
     Q.date = '2010-07-01' AND 
     Q.market = S.market AND 
     Q.ticker = S.ticker 

UNION 

SELECT T2.date1, T2.date2, T2.period, T1.market, T1.ticker, 0 AS scenario 
FROM 
(SELECT DISTINCT 
     Q.market AS market, 
     Q.ticker AS ticker 

     FROM portfolio.scenario S , portfolio.quote Q 
     WHERE Q.date = '2010-07-01' AND 
       Q.market = S.market AND 
       Q.ticker = S.ticker AND 
       S.series = (SELECT S.series 
        FROM scenario S 
        WHERE S.date1 >= '2009-09-01' AND 
         S.date2 <= '2010-07-01' AND 
         S.period = 'QUARTER' 
        ORDER BY S.date2 
        LIMIT 1) AND 
       S.date1 >= '2009-09-01' AND 
       S.date2 <= '2010-07-01') AS T1 

JOIN 

(SELECT DISTINCT S.date1, S.date2, S.period 
FROM scenario S 
WHERE S.series = (SELECT S.series 
        FROM scenario S 
        WHERE S.date1 >= '2009-09-01' AND 
         S.date2 <= '2010-07-01' AND 
         S.period = 'QUARTER' 
        ORDER BY S.date2 
        LIMIT 1) AND 
     S.date1 >= '2009-09-01' AND 
     S.date2 <= '2010-07-01') AS T2 


WHERE (T2.date1, T2.date2, T2.period, T1.market, T1.ticker) 
     NOT IN (SELECT S.date1 AS date1, 
       S.date2 AS date2, 
       S.period AS period, 
       Q.market AS market, 
       Q.ticker AS ticker 

     FROM portfolio.scenario S , portfolio.quote Q 
     WHERE Q.date = '2010-07-01' AND 
       Q.market = S.market AND 
       Q.ticker = S.ticker AND 
       S.series = (SELECT S.series 
        FROM scenario S 
        WHERE S.date1 >= '2009-09-01' AND 
         S.date2 <= '2010-07-01' AND 
         S.period = 'QUARTER' 
        ORDER BY S.date2 
        LIMIT 1) AND 
       S.date1 >= '2009-09-01' AND 
       S.date2 <= '2010-07-01') 


ORDER BY 
date1,date2,period,market,ticker 

@Bruce的評論和一些邏輯,現在減少一個子查詢我的查詢之後是:

(SELECT S.date1, 
     S.date2, 
     S.period, 
     Q.market, 
     Q.ticker, 
     Q.close * EXP(S.ratio) AS scenario 

FROM portfolio.scenario S , portfolio.quote Q 

WHERE 
     S.date1 >= (@date1 := '2009-09-01') AND 
     S.date2 <= (@date2 := '2010-07-01') AND 
     Q.date = (@qdate := '2010-07-01') AND 
     S.series = 
     (@series := 
        (SELECT S.series 
        FROM scenario S 
        WHERE S.date1 >= '2009-09-01' AND 
         S.date2 <= '2010-07-01' AND 
         S.period = 'QUARTER' 
        ORDER BY S.date2 
        LIMIT 1)) AND 
     Q.market = S.market AND 
     Q.ticker = S.ticker) 

UNION 

(SELECT T2.date1, T2.date2, T2.period, T1.market, T1.ticker, 0 AS scenario 
FROM 
(SELECT Q.market, Q.ticker 
FROM quote Q 
WHERE Q.date = @qdate) AS T1 

JOIN 

(SELECT DISTINCT S.date1, S.date2, S.period 
FROM scenario S 
WHERE S.series = @series AND 
     S.date1 >= @date1 AND 
     S.date2 <= @date2) AS T2 

WHERE (T2.date1, T2.date2, T2.period, T1.market, T1.ticker) 
     NOT IN 

     (SELECT S.date1, 
       S.date2, 
       S.period, 
       Q.market, 
       Q.ticker 
     FROM portfolio.scenario S , portfolio.quote Q 
     WHERE Q.date = @qdate AND 
       Q.market = S.market AND 
       Q.ticker = S.ticker AND 
       S.series = @series AND 
       S.date1 >= @date1 AND 
       S.date2 <= @date2)) 

但是,如果我改變

(@series := 
       (SELECT S.series 
       FROM scenario S 
       WHERE S.date1 >= '2009-09-01' AND 
        S.date2 <= '2010-07-01' AND 
        S.period = 'QUARTER' 
       ORDER BY S.date2 
       LIMIT 1)) 

(@series := 
       (SELECT S.series 
       FROM scenario S 
       WHERE S.date1 >= @date1 AND 
        S.date2 <= @date2 AND 
        S.period = 'QUARTER' 
       ORDER BY S.date2 
       LIMIT 1)) 

需要t處理它很多時間(我已經執行了查詢10分鐘前,仍然沒有得到結果),而查詢通常在5秒內返回。

另外,當我重置變量,執行結果不正確(可能使用前一次執行的變量值)。我怎樣才能改變這種不添加SET語句(我想這是一個單一的查詢)

回答

3

使用MySQL變量:

SELECT 
    @x := ColumnName, 
    @y := ColumnName2 + @z, 
    @z := (SELECT * FROM SubTable WHERE x = @x), 
    (SELECT * FROM Table2 WHERE X = @z), 
    (SELECT * FROM Table3 WHERE X = @z) 
FROM Table 
WHERE 
    v = @v 
  • 您可以分配的子查詢和列值SQL變量
  • 您可以在語句中的任意位置參考這些變量
  • 變量包含前一行的值(如果已設置)
  • 您可以以這種方式重新使用子查詢和其他值
+0

謝謝你的好建議,但在我的查詢中使用@z:=(SELECT * FROM SubTable WHERE x = @x)這樣的行大大增加了獲取結果集的時間。我已經重新編輯了這個問題,以包含基於您的評論和一些邏輯的新查詢以減少子查詢 – 3ashmawy 2010-11-19 22:22:39

+1

這些節省來自在許多列中使用該變量(我的示例沒有顯示,所以我更新了它) 。我最近將這個應用到了一段總結性的SQL,否則它會爲多列重複窗口平均計算(子選擇+分組函數)。 – 2010-11-19 22:44:30

+0

Thanx兄弟的反饋,是的,我用@series變量的概念。我想你的例子@z:=(SELECT * FROM SubTable WHERE x = @x),SubTable只有一列,因爲@z將無法保存來自多列的值。 – 3ashmawy 2010-11-19 23:18:06