MySQL Count子查询

时间:2012-07-02 16:40:32

标签: mysql sql subquery aggregate-functions

我有一个包含3个表的数据库:

  • 股票
  • stocksplits
  • 分红

股票和股票之间以及股票和股息之间存在一对多的关系。对于每个股权,我想显示股票分割和股息的数量:

SELECT equities.Symbol, 
       (SELECT COUNT(*) 
          FROM stocksplits 
         WHERE stocksplits.EquityID = equities.InstrumentID) as `# Splits`,
       (SELECT COUNT(*) 
          FROM dividends 
         WHERE dividends.EquityID = equities.InstrumentID) as `# Dividends`
FROM equities

查询似乎运行正常,但我怀疑它效率低下。怎样才能更快地重构?没有DBMS(通过.net到MySQL服务器的SQL查询),假设索引存在于每个表的主ID上。

3 个答案:

答案 0 :(得分:9)

计算PK而不是*可能已经有所帮助:

SELECT equities.Symbol, 
           (SELECT COUNT(stocksplitsID) 
              FROM stocksplits 
             WHERE stocksplits.EquityID =     equity.InstrumentID) as `# Splits`,
           (SELECT COUNT(dividendsid) 
              FROM dividends 
             WHERE dividends.EquityID = equities.InstrumentID) as `# Dividends`
FROM equities

答案 1 :(得分:1)

这是您的原始查询

SELECT equities.Symbol, 
       (SELECT COUNT(*) 
          FROM stocksplits 
         WHERE stocksplits.EquityID = equities.InstrumentID) as `# Splits`
FROM equities

我只是认为LEFT JOIN会更清洁

SELECT equities.Symbol,
    SUM(IF(IFNULL(stocksplits.EquityID,0)=0,0,1)) StockSplits,
    SUM(IF(IFNULL(dividends.EquityID  ,0)=0,0,1)) Dividends
FROM
    equities
    LEFT JOIN stocksplits ON equities.InstrumentID = stocksplits.EquityID
    LEFT JOIN dividends   ON equities.InstrumentID = dividends.EquityID
GROUP BY equities.Symbol;

IFNULL涵盖任何没有股票分裂的股票

尝试一下,看看它运行得更快

让我解释一下SUM(IF(IFNULL(stocksplits.EquityID,0)=0,0,1))

这个词
  • 如果LEFT JOIN在右侧表格中没有相应的条目,则IFNULL会将NULL变为0。
  • 如果LEFT JOIN有一个右侧条目,IF函数返回1
  • 如果LEFT JOIN没有右侧输入,则IF函数返回0
  • SUM会将所有的1和0相加,模拟COUNT

答案 2 :(得分:0)

在我的经验中,MySQL的correlated subquery表现不佳。

Q1 - 加入

SELECT t1.Symbol, t1.cnt_splits, t2.cnt_dividends
FROM (
    SELECT equities.Symbol AS Symbol, COUNT(*) AS cnt_splits
    FROM equities LEFT JOIN stocksplits
        ON stocksplits.EquityID = equities.InstrumentID
    GROUP BY equities.Symbol
) t1,
(
    SELECT equities.Symbol AS Symbol, COUNT(*) AS cnt_dividends
    FROM equities LEFT JOIN dividends
        dividends.EquityID = equities.InstrumentID
    GROUP BY equities.Symbol
) t2 ON t1.Symbol = t2.Symbol;

Q2 - UNION

Q1没有correlate subquery并产生与您相同的结果。但需要额外的连接,这需要时间。以下UNION模式更快,但输出应在客户端转换。

SELECT equities.Symbol AS Symbol, COUNT(*) AS cnt_splits
FROM equities LEFT JOIN stocksplits
    ON stocksplits.EquityID = equities.InstrumentID
GROUP BY equities.Symbol

UNION

SELECT equities.Symbol AS Symbol, COUNT(*) AS cnt_dividends
FROM equities LEFT JOIN dividends
    dividends.EquityID = equities.InstrumentID
GROUP BY equities.Symbol