2011-05-11 134 views
5
SELECT Trade.TradeId, Trade.Type, Trade.Symbol, Trade.TradeDate, 
     SUM(TradeLine.Notional)/1000 AS Expr1 
FROM Trade INNER JOIN 
      TradeLine ON Trade.TradeId = TradeLine.TradeId 
WHERE (TradeLine.Id IN 
         (SELECT  PairOffId 
         FROM   TradeLine AS TradeLine_1 
         WHERE  (TradeDate <= '2011-05-11') 
         GROUP BY PairOffId 
         HAVING  (SUM(Notional) <> 0))) 
GROUP BY Trade.TradeId, Trade.Type, Trade.Symbol, Trade.TradeDate 
ORDER BY Trade.Type, Trade.TradeDate 

当表开始增长时,我担心IN在WHERE子句中的性能。有没有人有这种查询更好的策略?子查询返回的记录数量增长得比TradeLine表中记录的数量慢得多。 TradeLine表格本身的增长速度为每天10个。查询性能WHERE子句包含IN(子查询)

谢谢。

编辑: 我使用了将子查询从WHERE移动到FROM的想法。我对所有对这个新查询做出贡献的答案投了赞成票。

SELECT Trade.TradeId, Trade.Type, Trade.Symbol, Trade.TradeDate, 
      PairOff.Notional/1000 AS Expr1 
    FROM   Trade INNER JOIN 
        TradeLine ON Trade.TradeId = TradeLine.TradeId INNER JOIN 
         (SELECT  PairOffId, SUM(Notional) AS Notional 
         FROM   TradeLine AS TradeLine_1 
         WHERE  (TradeDate <= '2011-05-11') 
         GROUP BY PairOffId 
        HAVING (SUM(Notional) <> 0)) AS PairOff ON TradeLine.Id = PairOff.PairOffId 
    ORDER BY Trade.Type, Trade.TradeDate 
+0

你不能颠倒顺序?将子查询作为外部查询运行,然后将外部查询作为子查询运行。 – soandos 2011-05-11 20:43:09

+0

@soandos - 你有什么想法RDBMS的工作? – JNK 2011-05-11 20:45:44

+0

是的,虽然不是很多。 (a) if(b) 其中外环比内环需要更多的时间。所以扭转他们给出了相同的结果,但更快 – soandos 2011-05-11 20:53:57

回答

5

IN子句中的子查询不依赖于外部查询任何东西。你可以放心地将它移动到FROM条款;一个健全的查询计划生成器会自动完成。

此外,在任何要用于生产的查询中调用EXPLAIN PLAN是必须的。做到这一点,看看DBMS对这个查询计划的看法。

2

当一个子查询开始返回太大的结果集时,我是临时表的粉丝。

所以你where条款也只是

Where TradeLine.Id In (Select PairOffId From #tempResults) 

#tempResults将被定义为(警告:语法是从内存,这意味着可能有误差)

Select PairOffId Into #tempResults 
From TradeLine 
Where (TradeDate <= @TradeDate) 
    //I prefer params in case the query becomes a StoredProc 
Group By PairOffId 
Having (Sum(Notional) <> 0) 
-1

使用In会本质上迫使你做表扫描。当你的表增长时,你的执行时间会增加。您还正在为返回的每个记录运行该查询。会更容易地使用标选择一个表:

SELECT t.TradeId, t.Type, t.Symbol, t.TradeDate, 
     SUM(TradeLine.Notional)/1000 AS Expr1 
FROM Trade t, 
(SELECT  TradeId, PairOffID 
         FROM   TradeLine AS TradeLine_1 
         WHERE  (TradeDate <= '2011-05-11') 
         GROUP BY PairOffId 
         HAVING  (SUM(Notional) <> 0)) tl  
WHERE t.TradeId = tl.TradeId 
    and t.id <> tl.PairOffID 
GROUP BY Trade.TradeId, Trade.Type, Trade.Symbol, Trade.TradeDate 
ORDER BY Trade.Type, Trade.TradeDate 
+2

-1因为'使用一个IN本质上会迫使你做一个表扫描。这并不准确。 – JNK 2011-05-11 20:57:12

+1

'IN'只是另一种类型的连接(半连接)。在'MySQL'中确实执行得很糟糕,并且[即使在不相关的情况下,它们也被重复评估为相关的子查询](http://stackoverflow.com/questions/3417074/why-would-an-in-condition-慢于-sql/3417190#3417190)但不在SQL Server中。你提出的重写也会改变语义。 – 2011-05-11 21:02:04

+0

架构中没有't.id'! – 2011-05-11 21:10:06

1

我有2个建议你可以试试:

1)。使用exists,因为你不需要从子查询中获取数据,如:

其中存在(从TRADELINE 选择1 AS TradeLine_1 其中TradeLine.Id = TradeLine_1.PairOffId - 继续与您的子查询.. )

2)。主查询加入到你的子查询,例如

...加入(your_subquery)上 your_subquery.PairOffId = TradeLine.Id

我相信这2种方法可以实现比 “在” 更好性能操作。

1

我在XXXXXX数据库中遇到了成千上万条记录的相同问题。在我的代码中,我想从所有节点检索层次结构(包含至少一个子节点的节点)。

enter image description here

写入的初始查询,这是非常缓慢的。

SELECT SUPPLIER_ID, PARENT_SUPPLIER_ID, 
    FROM SUPPLIER 
    WHERE 
    SUPPLIER_ID != PARENT_SUPPLIER_ID 
    OR 
    SUPPLIER_ID IN 
     (SELECT DISTINCT PARENT_SUPPLIER_ID 
     FROM SUPPLIER 
     WHERE SUPPLIER_ID != PARENT_SUPPLIER_ID 
    ); 

然后重新写入

SELECT a.SUPPLIER_ID, a.PARENT_SUPPLIER_ID, 
    FROM SUPPLIER a 
    LEFT JOIN 
    (SELECT DISTINCT PARENT_SUPPLIER_ID 
    FROM SUPPLIER 
    WHERE SUPPLIER_ID != PARENT_SUPPLIER_ID 
) b 
    ON a. SUPPLIER_ID  = b.PARENT_SUPPLIER_ID 
    WHERE a. SUPPLIER_ID != a.PARENT_SUPPLIER_ID 
    OR a. SUPPLIER_ID  = b.PARENT_SUPPLIER_ID;