如何使子查询更快,从表中选择具有2000万行的数据

时间:2016-03-05 11:22:39

标签: sql sql-server performance tsql subquery

这是我的查询。此查询导致20-30秒,并在我的应用程序中导致超时错误。我试图用条款重写,但我无法让它运行。

抱歉我的英语不好。

SELECT 
    StationName, StationID,
    (SELECT TOP (1) ISNULL(SUM(Liter), 0) AS TotalLiter 
     FROM Transactions  (nolock) 
     WHERE (StationID = s.StationID) 
       AND (SaleDate>= CONVERT(date, GETDATE())) 
       AND (FuelTypeID = 1)) AS Total1,
    (SELECT TOP (1) ISNULL(SUM(Liter), 0) AS TotalLiter
     FROM dbo.Transactions (nolock) AS Transactions_11 
     WHERE (StationID = s.StationID) 
       AND (SaleDate >= CONVERT(date, GETDATE())) 
       AND (FuelTypeID = 2)) AS Total2,
    (SELECT TOP (1) ISNULL(SUM(Liter), 0) AS TotalLiter
     FROM dbo.Transactions (nolock) AS Transactions_10
     WHERE (StationID = s.StationID) 
       AND (SaleDate >= CONVERT(date, GETDATE())) 
       AND (FuelTypeID = 3)) AS Total3,
    (SELECT TOP (1) ISNULL(SUM(Liter), 0) AS TotalLiter
     FROM dbo.Transactions (nolock) AS Transactions_9
     WHERE (StationID = s.StationID) 
       AND (SaleDate >= CONVERT(date, GETDATE())) 
       AND (FuelTypeID = 4)) AS Total4,
    (SELECT TOP (1) ISNULL(SUM(Liter), 0) AS TotalLiter
     FROM dbo.Transactions (nolock) AS Transactions_8
     WHERE (StationID = s.StationID) 
       AND (SaleDate >= CONVERT(date, GETDATE())) 
       AND (FuelTypeID = 5)) AS Total5,
                  (SELECT TOP (1) ISNULL(SUM(Liter),0) AS TotalLiter
                   FROM      dbo.Transactions  (nolock) AS Transactions_7
                   WHERE   (StationID = s.StationID) AND (SaleDate >= CONVERT(date, GETDATE())) AND (FuelTypeID = 6)) AS Total6,
                  (SELECT TOP (1) ISNULL(SUM(Liter),0) AS TotalLiter
                   FROM      dbo.Transactions  (nolock) AS Transactions_6
                   WHERE   (StationID = s.StationID) AND (SaleDate >= CONVERT(date, GETDATE())) AND (FuelTypeID = 7)) AS Total7,
                  (SELECT TOP (1) ISNULL(SUM(Liter),0) AS TotalLiter
                   FROM      dbo.Transactions  (nolock) AS Transactions_5
                   WHERE   (StationID = s.StationID) AND (SaleDate >= CONVERT(date, GETDATE())) AND (FuelTypeID = 8)) AS Total8,
                  (SELECT TOP (1) ISNULL(SUM(Liter),0) AS TotalLiter
                   FROM      dbo.Transactions  (nolock) AS Transactions_4
                   WHERE   (StationID = s.StationID) AND (SaleDate >= CONVERT(date, GETDATE())) AND (FuelTypeID = 9)) AS Total9,
                  (SELECT TOP (1) ISNULL(SUM(Liter),0) AS TotalLiter
                   FROM      dbo.Transactions  (nolock) AS Transactions_3
                   WHERE   (StationID = s.StationID) AND (SaleDate >= CONVERT(date, GETDATE())) AND (FuelTypeID = 10)) AS Total10,
                  (SELECT TOP (1) ISNULL(SUM(Liter),0) AS TotalLiter
                   FROM      dbo.Transactions  (nolock) AS Transactions_2
                   WHERE   (StationID = s.StationID) AND (SaleDate >= CONVERT(date, GETDATE()))) AS GrandTotal,
                  (SELECT TOP (1) MAX(SaleDate) AS LastSaleDate
                   FROM      dbo.Transactions (nolock) AS Transactions_1
WHERE   (StationID = s.StationID) AND (SaleDate >= CONVERT(date, GETDATE()))
                   ORDER BY LastSaleDate) AS LastSaleDate 
FROM    
    dbo.Stations (nolock) AS s 
WHERE 
    s.StationCode BETWEEN 1000 AND 1100 
ORDER BY 
    StationID

2 个答案:

答案 0 :(得分:4)

您可以使用Outer ApplyConditional Aggregate来避免多次运行相同的Sub-Query

尝试这样的事情

SELECT StationName,
       StationID,
       Total1,
       Total2,
       Total3,
       Total4
       ...
       GrandTotal,
       LastSaleDate
FROM   dbo.Stations (nolock) AS s
       OUTER apply (SELECT Sum(CASE WHEN t.FuelTypeID = 1 THEN Liter END) AS Total1,
                           Sum(CASE WHEN t.FuelTypeID = 2 THEN Liter END) AS Total2,
                           Sum(CASE WHEN t.FuelTypeID = 3 THEN Liter END) AS Total3,
                           Sum(CASE WHEN t.FuelTypeID = 4 THEN Liter END) AS Total4,
                           ... 
                           Sum(Liter) as GrandTotal,
                           Max(SaleDate) AS LastSaleDate
                    FROM   Transactions t
                    WHERE  t.StationID = s.StationID
                           AND t.SaleDate >= CONVERT(DATE, Getdate())) ou 
WHERE  s.StationCode BETWEEN 1000 AND 1100
ORDER  BY StationID 

也不要忘记阅读这篇文章:Bad habits : Putting NOLOCK everywhere

答案 1 :(得分:0)

    SELECT s.StationName, s.StationID,
           sum(Total6.ttl) as [Total6.ttl],
           sum(Total7.ttl) as [Total7.ttl],
           sum(Total8.ttl) as [Total8.ttl],
           sum(Total9.ttl) as [Total9.ttl],
           sum(TotalG.ttl) as [TotalG.ttl],
           max(TotalG.LastSaleDate) as [LastSaleDate.ttl],
      FROM dbo.Stations (nolock) AS s 
 LEFT JOIN Transactions Total6
             on  Total6.StationID = s.StationID 
            and  Total6.FuelTypeID = 6
            and  Total6.SaleDate >= CONVERT(DATE, Getdate()) 
 LEFT JOIN Transactions Total7
             on  Total7.StationID = s.StationID 
            and  Total7.FuelTypeID = 7
            and  Total7.SaleDate >= CONVERT(DATE, Getdate()) 
 LEFT JOIN Transactions Total8
             on  Total8.StationID = s.StationID 
            and  Total8.FuelTypeID = 8
            and  Total8.SaleDate >= CONVERT(DATE, Getdate()) 
 LEFT JOIN Transactions Total9
             on  Total9.StationID = s.StationID 
            and  Total9.FuelTypeID = 9
            and  Total9.SaleDate >= CONVERT(DATE, Getdate()) 
 LEFT JOIN Transactions TotalG
             on  TotalG.StationID = s.StationID 
            and  TotalG.SaleDate >= CONVERT(DATE, Getdate()) 
     WHERE s.StationCode BETWEEN 1000 AND 1100
  GROUP BY s.StationName, s.StationID