6

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

  • 股票
  • 股票分割
  • 股息

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

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 上。

4

3 回答 3

12

计算 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
于 2012-07-02T18:01:51.400 回答
2

这是您的原始查询

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
于 2012-07-02T16:48:56.793 回答
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 - 联合

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
于 2014-01-12T05:01:14.417 回答