2016-05-10 3 views
1

Я провел несколько исследований, и я пришел к выводу, что функция DATEDIFF делает мои запросы очень медленными.SQL Server - DATEDIFF Слишком длинная функция

Ниже представлен сгенерированный запрос Entity Framework, и он выглядит достаточно удобочитаемым.

Вот Linq, который генерирует T-SQL:

model.NewTotal1Week = (from sdo in context.SubscriberDebitOrders 
         where 
         (
          sdo.CampaignId == campaignId && 
          (sdo.Status == (Int32) DebitOrderStatus.New_Faulty) && 
          (SqlFunctions.DateDiff("week", sdo.Collections.FirstOrDefault(c => c.TxnStatus == "U").ProcessDate, DateTime.Now) <= 1) 
         ) 
         select sdo).Count(); 

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

Есть ли кто-нибудь, кто может помочь мне избавиться от функции DATEDIFF? Я видел примеры в Интернете, но я не мог приспособить его к моему сценарию, простите меня, я еще не очень гений.

exec sp_executesql N'SELECT 
    [GroupBy1].[A1] AS [C1] 
    FROM (SELECT 
     COUNT(1) AS [A1] 
     FROM [dbo].[SubscriberDebitOrder] AS [Extent1] 
     OUTER APPLY (SELECT TOP (1) 
      [Extent2].[ProcessDate] AS [ProcessDate] 
      FROM [dbo].[Collections] AS [Extent2] 
      WHERE ([Extent1].[Id] = [Extent2].[DebitOrderId]) AND (''U'' = [Extent2].[TxnStatus])) AS [Limit1] 
     WHERE ([Extent1].[CampaignId] = @p__linq__0) AND (3 = [Extent1].[Status]) AND ((DATEDIFF(week, [Limit1].[ProcessDate], SysDateTime())) <= 1) 
    ) AS [GroupBy1]',N'@p__linq__0 int',@p__linq__0=3 
go 

Заранее спасибо.

+0

показать код, который генерирует этот SQL. – Hakunamatata

+0

@Hakunamatata, я обновил свой OP с Linq, который генерирует T-SQL – Morgs

ответ

3

Это ваш запрос:

SELECT GroupBy1.A1 AS C1 
FROM (SELECT COUNT(1) AS[A1 
     FROM dbo.SubscriberDebitOrder AS Extent1 OUTER APPLY 
      (SELECT TOP (1) Extent2.ProcessDate 
      FROM [dbo].Collections Extent2 
      WHERE (Extent1.Id = Extent2.DebitOrderId AND 
        'U' = Extent2.TxnStatus 
      ) AS [Limit1] 
     WHERE (Extent1.CampaignId = @p__linq__0) AND (3 = Extent1.Status) AND 
      (DATEDIFF(week, Limit1.ProcessDate, SysDateTime()) <= 1) 
    ) GroupBy1; 

Как уже упоминалось в другом месте, вы должны изменить логику даты и избавиться от внешнего запроса:

 SELECT COUNT(1) AS A1 
     FROM dbo.SubscriberDebitOrder AS Extent1 OUTER APPLY 
      (SELECT TOP (1) Extent2.ProcessDate 
      FROM [dbo].Collections Extent2 
      WHERE (Extent1.Id = Extent2.DebitOrderId AND 
        'U' = Extent2.TxnStatus 
      ) AS limit1 
     WHERE (Extent1.CampaignId = @p__linq__0) AND (3 = Extent1.Status) AND 
      Limit1.ProcessDate <= DATEADD(-1, week, GETDATE()) 

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

Исходя из вашего описания, вышесказанное вернее.

Далее вы хотите индексы на Collections(DebitOrderId, TxnStatus, ProcessDate) и SubscriberDebitOrder(CampaignId, Status).

+0

мой SQL Server не позволяет мне: DATEADD (-1, неделя, GETDATE()). Однако я переключил его на DATEADD (неделя, -1, GETDATE()), и я не получаю никаких результатов, когда должен. Любое предложение, пожалуйста? – Morgs

+0

Gordon Linoff, спасибо, что заставило меня добавлять индексы в столбцы, которые вы предложили. Результаты теперь возвращаются менее чем за 5 секунд ... – Morgs

4

Его не просто DATEDIFF, любая функция в столбце будет вызывать запрос, чтобы сделать сканирование на основной таблицы/индекса

DATEDIFF(week, [Limit1].[ProcessDate], SysDateTime())) <=1 

Выше логики Fetching прошлой недели данные? Вы также можете написать выше, не помещая функцию вокруг столбца ProcessDate.

[Limit1].[ProcessDate] > SysDateTime()-7 
+2

Мне нравится ваше решение! +1 с моей стороны, но вам нужно было бы переключить SysDateTime на 'DATETIME' или лучше использовать' GETDATE() '... С' DATETIME2' вы не можете выполнять простые дополнения ... – Shnugo

+1

Логика для этого 'lateiff() 'не совсем то же самое, что и исходная логика. –

+0

Спасибо за указание GETDATE() ... @Balmukund Lakhani, я попробовал вам решение и заменил SysDateTime() на GETDATE(), и запрос все еще занимает 1 минуту. Это немного подкупает меня тем, что происходит. Кампания с id 27 в соответствии с OP имеет меньше Collection, только 1434. Когда я выполняю тот же запрос для другой кампании с более чем 40K коллекциями, запрос заканчивается менее чем за 30 секунд. Не слишком уверен, что здесь может происходить ... Любые предложения? – Morgs

Смежные вопросы