Почему применяется кросс-приложение, делая запрос медленным?

У меня есть запрос, который занимает около 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 ответов

Ваш запрос медленнее, потому что он соединяется с таблицей измерений, значительно увеличивая количество обрабатываемых данных. Вероятно, вы можете исправить этот запрос, убедившись, что у вас есть соответствующие индексы:

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

Если это не поможет, вам нужно будет пересмотреть запрос. Существует альтернативный способ записи, но индексы могут решить проблему более просто.


Я сам не знаком с 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


Можете ли вы попробовать изменить свой запрос, как показано ниже, а затем поделиться результатами (если вы заметили какие-либо улучшения)

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


Нужно ли быть перекрестным применением/подзапросом? Похоже, что он делает больше работы таким образом. Не могли ли они быть объединены?

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


У меня был аналогичный опыт с CROSS APPLY на сервере MS SQL при использовании на большой таблице в медицинском наборе данных. Я говорю о нескольких порядках увеличения времени выполнения при добавлении CROSS APPLY.

После небольшого исследования я обнаружил, что использование PIVOT было чрезвычайно эффективным, взяв запрос s > 18 часов до менее 2 минут (!), поэтому я решил поделиться этим советом 2c. Джо.

licensed under cc by-sa 3.0 with attribution.