代码之家  ›  专栏  ›  技术社区  ›  3ashmawy

如何使用重复子查询优化大型查询

  •  2
  • 3ashmawy  · 技术社区  · 14 年前

    我有以下包含重复子查询的大型查询,对我来说它看起来效率很低。如何优化它?

    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 's comment and some logic to reduce a subquery my query now is:

    (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))
    

    处理它花费了太多时间(我10分钟前执行了查询,但仍然没有得到结果),而查询通常在5秒钟内返回。

    另外,当我重置变量时,执行结果不正确(可能使用上一次执行中的变量值)。如何在不添加set语句的情况下更改它(我希望它是单个查询)

    1 回复  |  直到 14 年前
        1
  •  4
  •   Bruce Alderson    14 年前

    使用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
    
    • 可以将嵌套select和列值赋给SQL变量
    • 您可以在语句的任何地方引用这些变量
    • 变量包含前一行的值(如果已设置)
    • 您可以用这种方式重用子select和其他值