为什么交叉应用使查询变慢?

时间:2012-10-23 18:06:30

标签: sql sql-server sql-server-2008 tsql

我有一个查询,大约需要11秒才能运行一个日期。我希望运行相同的查询多天。换句话说,我希望能够返回多天的快照。这是我原来的疑问:

SELECT 
    COUNT(*) AS 'Number of Cars',
    d.ManufacturerName AS 'Make',
    d.Name AS 'Model', 
    c.name AS 'Car Class'
FROM CarRating a 
    INNER JOIN OwnedCar b ON a.OwnedCarID = b.OwnedCarID
    INNER JOIN CarClass c ON a.CarClassID = c.CarClassID
    INNER JOIN BaseCar d ON b.BaseCarID = d.BaseCarID

WHERE 
    @myDate < a.ExpiredWhen AND @myDate  >= a.EffectiveWhen 
GROUP BY 
    d.Name, c.name,d.ManufacturerName

就像我提到的查询需要11秒。为了对多个日期运行此查询,我使用日期表并将其交叉应用于上述查询:

SELECT [DATE], b.* FROM DimDate 
CROSS APPLY
    (SELECT 
        COUNT(*) AS 'Number of Cars',
        d.ManufacturerName AS 'Make',
        d.Name AS 'Model', 
        c.name AS 'Car Class'
    FROM CarRating a 
        INNER JOIN OwnedCar b ON a.OwnedCarID = b.OwnedCarID
        INNER JOIN CarClass c ON a.CarClassID = c.CarClassID
        INNER JOIN BaseCar d ON b.BaseCarID = d.BaseCarID

    WHERE 
    dimDate.Date < a.ExpiredWhen AND dimDate.Date >= a.EffectiveWhen    
    GROUP BY 
    d.Name, c.name,d.ManufacturerName) b

 WHERE DimDate.Date between @StartDate and @EndDate

即使是一天,此查询也需要49秒。为什么这么慢?有没有更好的方法呢?

5 个答案:

答案 0 :(得分:1)

您的查询速度较慢,因为它正在加入维度表,从而大大增加了正在处理的数据量。您可以通过确保具有适当的索引来修复此查询:

  • OwnedCar(OwnedCarId)
  • CarClass(CarClassId)
  • BaseCare(BaseCareID)
  • CarRating(EffectiveWhen,ExpiredWhen)

如果这没有帮助,那么您需要重新考虑查询。有一种替代方法可以编写它,但索引可以更简单地解决问题。

答案 1 :(得分:0)

我自己并不熟悉CROSS APPLY,但你不能只按照范围添加ExpiredWhen和分组,如下所示:

SELECT
     a.ExpiredWhen AS dimDate
   , COUNT(*) AS 'Number of Cars'
   , d.ManufacturerName AS 'Make'
   , d.Name AS 'Model'
   , c.name AS 'Car Class' 
FROM CarRating a
INNER JOIN OwnedCar b ON a.OwnedCarID = b.OwnedCarID
INNER JOIN CarClass c ON a.CarClassID = c.CarClassID
INNER JOIN BaseCar d ON b.BaseCarID = d.BaseCarID  
WHERE a.ExpiredWhen between @StartDate AND @EndDate
GROUP BY
   a.ExpiredWhen, d.Name, c.name, d.ManufacturerName

答案 2 :(得分:0)

您可以尝试按以下方式修改查询,然后分享结果(如果您观察到任何改进)

SELECT [DATE], b.* FROM DimDate 
CROSS APPLY
    (SELECT 
        **COUNT(1)** AS 'Number of Cars',
        d.ManufacturerName AS 'Make',
        d.Name AS 'Model', 
        c.name AS 'Car Class'
    FROM CarRating a 
        INNER JOIN OwnedCar b ON a.OwnedCarID = b.OwnedCarID
        **AND  dimDate.Date < a.ExpiredWhen AND dimDate.Date >= a.EffectiveWhen**   
        INNER JOIN CarClass c ON a.CarClassID = c.CarClassID
        INNER JOIN BaseCar d ON b.BaseCarID = d.BaseCarID

    GROUP BY 
    d.Name, c.name,d.ManufacturerName) b

 WHERE DimDate.Date between @StartDate and @EndDate

答案 3 :(得分:0)

它真的需要是交叉应用/子查询吗?看起来它正以这种方式做更多的工作。难道不能留下加入吗?

SELECT 
    dimDate.[Date]
    COUNT(1) AS 'Number of Cars',
    d.ManufacturerName AS 'Make',
    d.Name AS 'Model', 
    c.name AS 'Car Class'
FROM DimDate
LEFT OUTER JOIN CarRating a ON dimDate.[Date] < a.ExpiredWhen AND dimDate.[Date] >= a.EffectiveWhen 
LEFT OUTER JOIN OwnedCar b ON a.OwnedCarID = b.OwnedCarID
LEFT OUTER JOIN CarClass c ON a.CarClassID = c.CarClassID
LEFT OUTER JOIN BaseCar d ON b.BaseCarID = d.BaseCarID
GROUP BY dimDate.[Date], d.Name, c.name,d.ManufacturerName

答案 4 :(得分:0)

当在医疗数据集中的大型表上使用时,我在MS SQL服务器中与CROSS APPLY有类似的经历。我在谈论添加CROSS APPLY时执行时间增加了几个数量级。

经过一番探索后,我发现使用PIVOT非常有效,从&gt;开始查询18小时到2分钟(!)所以我想我会分享这个2c小费。乔。