SQL Server 2008: очень низкая производительность запросов при работе с определенной границей даты - PullRequest
2 голосов
/ 16 ноября 2009

Да, это странно.

У нас есть веб-сервис, который возвращает данные клиенту Silverlight. Запросы генерируются для базы данных SQL Server 2008 с использованием структуры сущностей. Большинство этих запросов основаны на диапазоне дат - например, извлекайте результаты между этой датой и той. Кроме того, представление используется для облегчения работы.

Мы заметили, что при выдаче определенного набора запросов, которые начинаются в или после определенной даты, выполнение будет очень медленным. Эта дата 5 ноября любого года. Если наша дата начала на один день раньше, исполнение будет мгновенным. Итак, 5-6, медленный. 4-6 - быстрый.

Вот SQL, который генерирует EF:

ЭТОТ ЗАПРОС БУДЕТ ОЧЕНЬ МЕДЛЕННЫМ (30 секунд)

SELECT 
1 AS [C1], 
[GroupBy1].[K1] AS [Name], 
[GroupBy1].[A1] AS [C2]
FROM ( SELECT 
[Extent1].[Name] AS [K1], 
SUM([Extent1].[Value]) AS [A1]
FROM (SELECT 
  [view_answers].[Value] AS [Value], 
  [view_answers].[Comment] AS [Comment], 
  [view_answers].[NewStockist] AS [NewStockist], 
  [view_answers].[NewDistPoint] AS [NewDistPoint], 
  [view_answers].[VoucherUsed] AS [VoucherUsed], 
  [view_answers].[CashTotal] AS [CashTotal], 
  [view_answers].[AnswerType] AS [AnswerType], 
  [view_answers].[StartTime] AS [StartTime], 
  [view_answers].[ActualEndTime] AS [ActualEndTime], 
  [view_answers].[Complete] AS [Complete], 
  [view_answers].[UserID] AS [UserID], 
  [view_answers].[UserName] AS [UserName], 
  [view_answers].[QuestionType] AS [QuestionType], 
  [view_answers].[ProductSKU] AS [ProductSKU], 
  [view_answers].[BrandID] AS [BrandID], 
  [view_answers].[TeamID] AS [TeamID], 
  [view_answers].[Name] AS [Name], 
  [view_answers].[Stage] AS [Stage], 
  [view_answers].[Question] AS [Question]
  FROM [dbo].[view_answers] AS [view_answers]) AS [Extent1]
  WHERE 
     ([Extent1].[UserID] = '16E3692F-806E-40A0-BB99-ABBBCC13060D') 
     AND (N'Distribution Points' = [Extent1].[QuestionType]) 
     AND ([Extent1].[StartTime] >= '11/05/2009 00:00:00') 
     AND ([Extent1].[StartTime] <= '11/08/2009 00:00:00') 
     AND (1 = [Extent1].[Complete]) 
     AND (2 = [Extent1].[BrandID]) 
     AND (N'Distribution Points' = [Extent1].[QuestionType])
  GROUP BY 
     [Extent1].[Name])  
  AS [GroupBy1]

ЭТО ОДИН БУДЕТ МНОГО БЫСТРЕЕ

    SELECT 
    1 AS [C1], 
    [GroupBy1].[K1] AS [Name], 
    [GroupBy1].[A1] AS [C2]
    FROM ( SELECT 
    [Extent1].[Name] AS [K1], 
    SUM([Extent1].[Value]) AS [A1]
    FROM (SELECT 
      [view_answers].[Value] AS [Value], 
      [view_answers].[Comment] AS [Comment], 
      [view_answers].[NewStockist] AS [NewStockist], 
      [view_answers].[NewDistPoint] AS [NewDistPoint], 
      [view_answers].[VoucherUsed] AS [VoucherUsed], 
      [view_answers].[CashTotal] AS [CashTotal], 
      [view_answers].[AnswerType] AS [AnswerType], 
      [view_answers].[StartTime] AS [StartTime], 
      [view_answers].[ActualEndTime] AS [ActualEndTime], 
      [view_answers].[Complete] AS [Complete], 
      [view_answers].[UserID] AS [UserID], 
      [view_answers].[UserName] AS [UserName], 
      [view_answers].[QuestionType] AS [QuestionType], 
      [view_answers].[ProductSKU] AS [ProductSKU], 
      [view_answers].[BrandID] AS [BrandID], 
      [view_answers].[TeamID] AS [TeamID], 
      [view_answers].[Name] AS [Name], 
      [view_answers].[Stage] AS [Stage], 
      [view_answers].[Question] AS [Question]
      FROM [dbo].[view_answers] AS [view_answers]) AS [Extent1]
    WHERE 
       ([Extent1].[UserID] = '16E3692F-806E-40A0-BB99-ABBBCC13060D') 
       AND (N'Distribution Points' = [Extent1].[QuestionType]) 
       AND ([Extent1].[StartTime] >= '11/04/2009 00:00:00') 
       AND ([Extent1].[StartTime] <= '11/08/2009 00:00:00') 
       AND (1 = [Extent1].[Complete]) 
       AND (2 = [Extent1].[BrandID]) 
       AND (N'Distribution Points' = [Extent1].[QuestionType])
    GROUP BY 
       [Extent1].[Name])  
    AS [GroupBy1]

Если мы установим дату начала 5 ноября прошлого года, выполнение будет медленным, 4 ноября прошлого года и снова быстрым. Глядя на данные в базе данных нет ничего необычного вокруг 5-го. Кроме того, кажется, что запросы с датой начала после 5-го числа будут выполняться медленно.

Я в тупике!

(база данных размещена удаленно, поэтому у меня нет прямого доступа к ней)

UPDATE

Спасибо за ответ, ребята. Во-первых, я, вероятно, должен прояснить, что мои знания о сервере sql очень важны. Я создаю базы данных разного качества, а затем использую что-то вроде Linq To SQL или EF для работы с ними. Так что я чувствую себя немного не в своей тарелке.

Относительно объединений - представление, которое я запрашиваю, включает данные из 6-7 таблиц. В следующий раз я постараюсь взять статистику на работе и добавить здесь дополнительную информацию. Я не очень много знаю о планах выполнения, или я вижу их в SQL Server Management Studio

UPDATE Статистика из медленного запроса (Затронуты 3 строки)

Table 'tblProducts'. Scan count 0, logical reads 22, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblQuestionTypes'. Scan count 0, logical reads 1496, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblQuestions'. Scan count 0, logical reads 1496, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblSessions'. Scan count 0, logical reads 28551, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblAnswers'. Scan count 1, logical reads 1976256, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblCalls'. Scan count 1, logical reads 439, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblUsers'. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Статистика быстрого запроса

Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblAnswers'. Scan count 1, logical reads 7008, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblProducts'. Scan count 0, logical reads 22, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblQuestions'. Scan count 1, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblQuestionTypes'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblCalls'. Scan count 1, logical reads 439, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblSessions'. Scan count 1, logical reads 47, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblUsers'. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

UPDATE План выполнения запроса (для меня новость) предполагает добавление нового индекса в строку в одной из таблиц - questionid в таблице ответов. Предлагаемый sql выглядит следующим образом:

USE [brandfourcoke]
GO
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[tblAnswers] ([QuestionID])
INCLUDE ([CallID],[Value])
GO

Расчетное улучшение стоимости запроса составляет 93%. Должен ли я пойти дальше и сделать это? База данных находится в живом окружении и использует отслеживание изменений SQL Server 2008 и структуру синхронизации. Поэтому я всегда беспокоился о том, что изменения в базе данных повлияют на отслеживаемые данные и сломают вещи для моих клиентов. Будет ли добавление данных отслеживания изменений сброса индекса? Спасибо за вашу помощь, ребята. Я чувствую себя полным новичком здесь.

Ответы [ 3 ]

5 голосов
/ 16 ноября 2009

Запустите медленный и быстрый запрос с помощью SET sTATISTICS IO ON и посмотрите, есть ли существенная разница в количестве логических чтений / физических чтений между ними.

Скорее всего, в данных наблюдается сильный перекос. Например, план на быстром выполняет вложенный цикл, управляемый результатом 10 строк (в результате 10 вложенных поисков), в то время как медленный внезапно видит 10000 строк, из которых предыдущий видел 10, что приводит к 10000 поискам. Хотя в вашем запросе нет объединений, механизм может использовать различные индексы доступа и объединять индексы с индексом кластера. Фактический план выполнения всегда будет точно показывать, что происходит.

4 голосов
/ 16 ноября 2009

Не зная ничего дополнительного, первое предположение состоит в том, что вы, вероятно, либо достигли критической точки использования индекса для конкретной операции, либо имеете устаревшую / неправильную статистическую информацию о распределении для данного столбца (столбцов). Это могут быть и другие вещи, такие как неоптимальное индексирование (возможно, неправильное, возможно, неправильно задан ключ и т. Д.), Учитывая, что вы используете Sql 2008, уверены ли вы, что не создали отфильтрованный индекс, а не традиционный полный индекс на конкретный столбец (столбцы) и т. д. - однако, чтобы определить это, нам нужно увидеть намного больше информации (например, схемы, индексы, планы запросов, распределение данных, статистика и т. д.).

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

0 голосов
/ 16 ноября 2009

Этот запрос является одной из причин, почему использование сгенерированного sql часто является ужасной идеей. Насколько я могу судить, это эквивалентный запрос, если вы написали его сами:

     SELECT 1 AS [C1],     
            [view_answers].[Name] AS [K1],     
            SUM([view_answers].[Value]) AS [C2]   
     FROM  [view_answers] 
     WHERE ([view_answers].[UserID] = '16E3692F-806E-40A0-BB99-ABBBCC13060D')        
     AND (N'Distribution Points' = [view_answers].[QuestionType])        
     AND ([view_answers].[StartTime] >= '11/04/2009 00:00:00')        
     AND ([view_answers].[StartTime] <= '11/08/2009 00:00:00')        
     AND (1 = [view_answers].[Complete])        
     AND (2 = [view_answers].[BrandID])        
     AND (N'Distribution Points' = [view_answers].[QuestionType])    
     GROUP BY        [view_answers].[Name]         

Попробуйте это с обеими датами и посмотрите, получаете ли вы те же результаты и ту же задержку при использовании 5 ноября. Какие поля индексируются?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...