2010-11-19 236 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