Устранение неполадок с запросом, производительность которого значительно различается между двумя серверами

Применяется к: SQL Server

В этой статье приведены действия по устранению неполадок с производительностью, когда запрос выполняется медленнее на одном сервере, чем на другом сервере.

Симптомы

Предположим, что установлены два сервера с установленным SQL Server. Один из экземпляров SQL Server содержит копию базы данных в другом экземпляре SQL Server. При выполнении запроса к базам данных на обоих серверах запрос выполняется медленнее на одном сервере, чем на другом.

Следующие действия помогут устранить эту проблему.

Шаг 1. Определение распространенных проблем с несколькими запросами

Используйте один из следующих двух методов для сравнения производительности для двух или нескольких запросов на двух серверах:

  • Вручную протестируйте запросы на обоих серверах:

    1. Выберите несколько запросов для тестирования, особое внимание уделите запросам, которые:
      • Значительно быстрее на одном сервере, чем на другом.
      • Важно для пользователя или приложения.
      • Часто используется или предназначено для воспроизведения проблемы по требованию.
      • Достаточно долго для записи данных в нем (например, вместо запроса в 5 миллисекунд, выберите запрос на 10 секунд).
    2. Запустите запросы на двух серверах.
    3. Сравните истекшее время (длительность) на двух серверах для каждого запроса.
  • Анализ данных производительности с помощью SQL Nexus.

    1. Сбор данных PSSDiag/SQLdiag или SQL LogScout для запросов на двух серверах.
    2. Импортируйте собранные файлы данных с помощью Sql Nexus и сравнивайте запросы с двух серверов. Дополнительные сведения см. в разделе "Сравнение производительности" между двумя коллекциями журналов (например, медленный и быстрый).

Сценарий 1. Только один запрос выполняется по-разному на двух серверах

Если только один запрос выполняется по-разному, проблема, скорее всего, относится к отдельному запросу, а не к среде. В этом случае перейдите к шагу 2. Сбор данных и определение типа проблемы с производительностью.

Сценарий 2. Несколько запросов выполняются по-разному на двух серверах

Если несколько запросов выполняются медленнее на одном сервере, чем другой, наиболее вероятной причиной являются различия в сервере или среде данных. Перейдите к разделу "Диагностика различий в среде" и убедитесь, что сравнение между двумя серверами является допустимым.

Шаг 2. Сбор данных и определение типа проблемы с производительностью

Сбор затраченного времени, времени ЦП и логических чтений

Чтобы собрать истекшее время и время ЦП запроса на обоих серверах, используйте один из следующих методов, наиболее подходящих для вашей ситуации:

  • Для текущих инструкций проверьте total_elapsed_time и cpu_time столбцы в sys.dm_exec_requests. Выполните следующий запрос, чтобы получить данные:

    SELECT 
        req.session_id
        , req.total_elapsed_time AS duration_ms
        , req.cpu_time AS cpu_time_ms
        , req.total_elapsed_time - req.cpu_time AS wait_time
        , req.logical_reads
        , SUBSTRING (REPLACE (REPLACE (SUBSTRING (ST.text, (req.statement_start_offset/2) + 1, 
           ((CASE statement_end_offset
               WHEN -1
               THEN DATALENGTH(ST.text)  
               ELSE req.statement_end_offset
             END - req.statement_start_offset)/2) + 1) , CHAR(10), ' '), CHAR(13), ' '), 
          1, 512)  AS statement_text  
    FROM sys.dm_exec_requests AS req
        CROSS APPLY sys.dm_exec_sql_text(req.sql_handle) AS ST
    ORDER BY total_elapsed_time DESC;
    
  • Для прошлых выполнений запроса проверьте столбцы last_elapsed_time и last_worker_time в sys.dm_exec_query_stats. Выполните следующий запрос, чтобы получить данные:

    SELECT t.text,
         (qs.total_elapsed_time/1000) / qs.execution_count AS avg_elapsed_time,
         (qs.total_worker_time/1000) / qs.execution_count AS avg_cpu_time,
         ((qs.total_elapsed_time/1000) / qs.execution_count ) - ((qs.total_worker_time/1000) / qs.execution_count) AS avg_wait_time,
         qs.total_logical_reads / qs.execution_count AS avg_logical_reads,
         qs.total_logical_writes / qs.execution_count AS avg_writes,
         (qs.total_elapsed_time/1000) AS cumulative_elapsed_time_all_executions
    FROM sys.dm_exec_query_stats qs
         CROSS apply sys.Dm_exec_sql_text (sql_handle) t
    WHERE t.text like '<Your Query>%'
    -- Replace <Your Query> with your query or the beginning part of your query. The special chars like '[','_','%','^' in the query should be escaped.
    ORDER BY (qs.total_elapsed_time / qs.execution_count) DESC
    

    Примечание.

    Если avg_wait_time отображается отрицательное значение, это параллельный запрос.

  • Если вы можете выполнить запрос по запросу в SQL Server Management Studio (SSMS), sqlcmd или расширение MSSQL для Visual Studio Code, запустите его с помощью SET STATISTICS TIMEON и SET STATISTICS IOON.

    SET STATISTICS TIME ON
    SET STATISTICS IO ON
    <YourQuery>
    SET STATISTICS IO OFF
    SET STATISTICS TIME OFF
    

    Затем из сообщений вы увидите время ЦП, истекшее время и логические операции чтения, как показано ниже:

      Table 'tblTest'. Scan count 1, logical reads 3, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.
    
      SQL Server Execution Times:
        CPU time = 460 ms,  elapsed time = 470 ms.
    
  • Если вы можете собрать план запроса, проверьте данные из свойств плана выполнения.

    1. Запустите запрос с включенной опцией Фактический план выполнения.

    2. Выберите левый оператор из плана выполнения.

    3. В разделе Свойства раскройте пункт QueryTimeStats.

    4. Проверьте elapsedTime и CpuTime.

      Снимок экрана: окно свойств плана выполнения SQL Server с развернутыми свойствами QueryTimeStats.

Сравните истекшее время и время ЦП запроса, чтобы определить тип проблемы для обоих серверов.

Тип 1: привязка ЦП (runner)

Если время ЦП близко, равно или выше, чем истекшее время, его можно рассматривать как запрос, привязанный к ЦП. Например, если истекшее время составляет 3000 миллисекунд (мс), а время ЦП равно 2900 мс, это означает, что большая часть истекшего времени тратится на ЦП. Затем можно сказать, что это запрос, привязанный к ЦП.

Примеры выполнения запросов с привязкой к ЦП:

Истекшее время (мс) Время ЦП (мс) Операции чтения (логические)
3200 3000 300 000
1080 1000 20

Логические операции чтения — чтение страниц данных и индексов в кэше — чаще всего являются драйверами использования ЦП в SQL Server. В некоторых случаях использование ЦП происходит из других источников: цикл while (в T-SQL или другом коде, таком как XProcs или объекты SQL CLR). Второй пример в таблице иллюстрирует такой сценарий, когда большинство загрузки ЦП не связано с операциями чтения.

Примечание.

Если время ЦП больше длительности, это означает, что выполняется параллельный запрос; Одновременно используется несколько потоков ЦП. Дополнительные сведения см. в разделе Параллельные запросы — исполнитель или ожидатель.

Тип 2. Ожидание узких мест (официант)

Запрос ожидает на узкое место, если истекшее время значительно превышает время работы ЦП. Истекшее время включает время выполнения запроса на ЦП (время ЦП) и время ожидания освобождения ресурса (время ожидания). Например, если истекшее время составляет 2000 мс, а время ЦП составляет 300 мс, время ожидания составляет 1700 мс (2000 – 300 = 1700). Дополнительные сведения см. в разделе "Типы ожиданий".

Примеры ожидающих запросов:

Истекшее время (мс) Время ЦП (мс) Операции чтения (логические)
2000 300 28000
10 080 700 80 000

Параллельные запросы — исполнитель или ожидатель

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

  • Если истекшее время значительно превышает время ЦП, считайте это ожиданием.
  • Если время ЦП значительно больше, чем время выполнения, рассмотрите это как процесс.

Примеры параллельных запросов:

Истекшее время (мс) Время ЦП (мс) Операции чтения (логические)
1200 8100 850000
3080 12300 1 500 000

Шаг 3. Сравнение данных с обоих серверов, определение сценария и устранение неполадок

Предположим, что существует два компьютера с именем Server1 и Server2. Запрос выполняется медленнее на сервере 1, чем на сервере Server2. Сравните время с обоих серверов, а затем следуйте действиям сценария, который лучше всего соответствует вашим параметрам из следующих разделов.

Сценарий 1. Запрос на сервере1 использует больше времени ЦП, а логические операции чтения выше на Сервере1, чем на Сервере2.

Если время ЦП на Server1 значительно больше, чем на Server2, и истекшее время точно соответствует времени ЦП на обоих серверах, на обоих серверах нет крупных ожиданий или узких мест. Увеличение времени ЦП на сервере 1, скорее всего, вызвано увеличением логических операций чтения. Значительное изменение логических операций чтения обычно указывает на разницу в планах запросов. Например:

Сервер Истекшее время (мс) Время ЦП (мс) Операции чтения (логические)
Server1 3100 3000 300 000
Server2 1 100 1000 90200

Действие: Проверка планов выполнения и среды

  1. Сравните планы выполнения запроса на обоих серверах. Для этого используйте один из двух методов:
  2. Сравнение сред. Различные среды могут привести к различиям в плане запросов или прямым различиям в использовании ЦП. Среды включают версии сервера, параметры конфигурации базы данных или сервера, флаги трассировки, количество ЦП или тактовую частоту, а также виртуальную или физическую машину. Дополнительные сведения см. в разделе "Диагностика различий в плане запросов".

Сценарий 2. Запрос является процессом ожидания на сервере Server1, но не на сервере Server2

Если время ЦП для запроса на обоих серверах аналогично, но истекшее время на Server1 гораздо больше, чем на Сервере 2, запрос на Сервер1 тратит гораздо больше времени на ожидание узких мест. Например:

Сервер Истекшее время (мс) Время ЦП (мс) Операции чтения (логические)
Server1 4500 1000 90200
Server2 1 100 1000 90200
  • Время ожидания сервера 1: 4500 – 1000 = 3500 мс
  • Время ожидания на Сервере 2: 1100 – 1000 = 100 мс

Действие. Проверка типов ожидания на Сервере1

Определение и устранение узких мест на сервере Server1. Примеры ожиданий: блокирование (ожидания блокировки), ожидания защелок, ожидания ввода-вывода диска, ожидания сети и ожидания памяти. Чтобы устранить распространенные проблемы с узкими местами, перейдите к Диагностика ожиданий или узких мест.

Сценарий 3: Запросы на обоих серверах – это ожидающие процессы, но типы или время ожидания отличаются.

Например:

Сервер Истекшее время (мс) Время ЦП (мс) Операции чтения (логические)
Server1 8000 1000 90200
Server2 3000 1000 90200
  • Время ожидания сервера 1: 8000 – 1000 = 7000 мс
  • Время ожидания на Сервере 2: 3000 – 1000 = 2000 мс

В этом случае время ЦП совпадает на обоих серверах, что означает, что планы запросов, скорее всего, одинаковы. Запросы будут выполняться одинаково на обоих серверах, если они не ожидают узких мест. Таким образом, различия длительности исходят из различных объемов времени ожидания. Например, запрос ожидает блокировки на сервере Server1 в течение 7000 мс, пока он ожидает ввода-вывода на сервере Server2 в течение 2000 мс.

Действие. Проверка типов ожидания на обоих серверах

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

Сценарий 4: Запрос на Server1 использует больше времени работы ЦП, чем на Server2, но логические чтения почти равны.

Например:

Сервер Истекшее время (мс) Время ЦП (мс) Операции чтения (логические)
Server1 3000 3000 90200
Server2 1000 1000 90200

Если данные соответствуют следующим условиям:

  • Время ЦП на Сервере1 гораздо больше, чем на Сервере 2.
  • Затраченное время тесно соответствует времени обработки ЦП на всех серверах, что свидетельствует об отсутствии задержек.
  • Логические операции чтения, как правило, являются наибольшим фактором использования процессора и аналогичны на обоих серверах.

Затем дополнительное время ЦП обусловлено некоторыми другими действиями, зависящими от ЦП. Этот сценарий является самым редким из всех сценариев.

Причины: трассировка, функции, определяемые пользователем (UDF) и интеграция CLR

Эта проблема может быть вызвана следующими причинами:

  • Трассировка XEvents/SQL Server, в особенности с фильтрацией по текстовым столбцам (имя базы данных, имя пользователя, текст запроса и т. д.). Если трассировка включена на одном сервере, но не на другом, это может быть причиной разницы.
  • Определяемые пользователем функции (UDFS) или другой код T-SQL, выполняющий операции, связанные с ЦП. Обычно это может быть причиной, когда другие условия отличаются на сервере Server1 и Server2, таких как размер данных, скорость ЦП или план питания.
  • Интеграция CLR SQL Server или расширенные хранимые процедуры (XPs), которые могут влиять на загрузку ЦП, но не выполнять логические операции чтения. Различия в библиотеках DLL могут привести к разному времени ЦП.
  • Разница в функциональных возможностях SQL Server, привязанных к ЦП (например, коду строковой манипуляции).

Действие: Проверка трассировок и запросов

  1. Проверьте трассировку на обоих серверах следующим образом:

    1. Если на Server1 включена трассировка, но не на Server2.
    2. Если любая трассировка включена, отключите трассировку и снова запустите запрос на сервере Server1.
    3. Если запрос выполняется быстрее на этот раз, включите трассировку обратно, но удалите из него фильтры текста, если есть какие-либо.
  2. Проверьте, использует ли запрос функции, определяемые пользователем (UDF), для манипуляций со строками или обширной обработки данных в столбцах списка SELECT.

  3. Проверьте, содержит ли запрос циклы, рекурсии функций или вложенные элементы.

Диагностика различий среды

Проверьте следующие вопросы и определите, является ли сравнение двух серверов допустимым.

  • Являются ли два экземпляра SQL Server одинаковыми версиями или сборками?

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

    SELECT @@VERSION
    
  • Совпадает ли объем физической памяти на обоих серверах?

    Если на одном сервере имеется 64 ГБ памяти, а другой — 256 ГБ памяти, это было бы существенной разницей. С большим объемом памяти, доступной для кэширования страниц данных и индексов и планов запросов, запрос можно оптимизировать по-разному на основе доступности аппаратных ресурсов.

  • Похожи ли конфигурации оборудования, связанные с ЦП, на обоих серверах? Например:

    • Количество ЦП зависит от компьютеров (24 ЦП на одном компьютере и 96 ЦП на другом).

    • Энергопланы — сбалансированный и высокая производительность.

    • Виртуальная машина (ВМ) и физическая машина (на голом железе).

    • Hyper-V и VMware — разница в конфигурации.

    • Разница скорости часов (более низкая скорость часов и более высокая скорость часов). Например, 2 ГГц и 3,5 ГГц могут иметь разницу. Чтобы получить скорость часов на сервере, выполните следующую команду PowerShell:

      Get-CimInstance Win32_Processor | Select-Object -Expand MaxClockSpeed
      

    Используйте один из следующих двух способов проверки скорости ЦП серверов. Если они не создают сопоставимые результаты, проблема выходит за пределы SQL Server. Это может быть разница в плане питания, меньше ЦП, проблема программного обеспечения виртуальной машины или разница скорости часов.

    • Выполните следующий скрипт PowerShell на обоих серверах и сравните выходные данные.

      $bf = [System.DateTime]::Now
      for ($i = 0; $i -le 20000000; $i++) {}
      $af = [System.DateTime]::Now
      Write-Host ($af - $bf).Milliseconds " milliseconds"
      Write-Host ($af - $bf).Seconds " Seconds"
      
    • Выполните следующий код Transact-SQL на обоих серверах и сравните выходные данные.

      SET NOCOUNT ON 
      DECLARE @spins INT = 0
      DECLARE @start_time DATETIME = GETDATE(), @time_millisecond INT
      
      WHILE (@spins < 20000000)
      BEGIN
         SET @spins = @spins +1
      END
      
      SELECT @time_millisecond = DATEDIFF(millisecond, @start_time, getdate())
      
      SELECT @spins Spins, @time_millisecond Time_ms,  @spins / @time_millisecond Spins_Per_ms
      

Диагностика задержек или узких мест

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

Чтобы вычислить приблизительное время ожидания, вычитайте время ЦП (рабочий период) из истекшего времени запроса. Как правило, время ЦП — это фактическое время выполнения, а оставшаяся часть времени выполнения запроса — ожидание.

Примеры вычисления приблизительной длительности ожидания:

Истекшее время (мс) Время ЦП (мс) Время ожидания (мс)
3200 3000 200
7080 1000 6080

Определение узкого места или времени ожидания

  • Чтобы определить исторические длительные запросы (например, >20% от общего времени ожидания), выполните следующий запрос. Этот запрос использует статистику производительности для кэшированных планов запросов с момента начала SQL Server.

    SELECT t.text,
             qs.total_elapsed_time / qs.execution_count
             AS avg_elapsed_time,
             qs.total_worker_time / qs.execution_count
             AS avg_cpu_time,
             (qs.total_elapsed_time - qs.total_worker_time) / qs.execution_count
             AS avg_wait_time,
             qs.total_logical_reads / qs.execution_count
             AS avg_logical_reads,
             qs.total_logical_writes / qs.execution_count
             AS avg_writes,
             qs.total_elapsed_time
             AS cumulative_elapsed_time
    FROM sys.dm_exec_query_stats qs
             CROSS apply sys.Dm_exec_sql_text (sql_handle) t
    WHERE (qs.total_elapsed_time - qs.total_worker_time) / qs.total_elapsed_time
             > 0.2
    ORDER BY qs.total_elapsed_time / qs.execution_count DESC
    
  • Чтобы определить выполнение запросов с ожиданием дольше 500 мс, выполните следующий запрос:

    SELECT r.session_id, r.wait_type, r.wait_time AS wait_time_ms
    FROM sys.dm_exec_requests r 
       JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id 
    WHERE wait_time > 500
    AND is_user_process = 1
    
  • Если вы можете собрать план запроса, проверьте WaitStats из свойств плана выполнения в SSMS:

    1. Запустите запрос с включением Плана фактического выполнения.
    2. Щелкните правой кнопкой мыши самый левый оператор на вкладке План выполнения
    3. Выберите "Свойства ", а затем свойство WaitStats .
    4. Проверьте waitTimeMs и WaitType.
  • Если вы знакомы с сценариями PSSDiag/SQLdiag или SQL LogScout LightPerf/GeneralPerf, рассмотрите возможность использования любого из них для сбора статистики производительности и определения ожиданий запросов на экземпляре SQL Server. Вы можете импортировать собранные файлы данных и проанализировать данные производительности с помощью SQL Nexus.

Ссылки на устранение или сокращение ожиданий

Причины и решения для каждого типа ожидания различаются. Не существует общего метода для разрешения всех типов ожидания. Ниже приведены статьи по диагностике и устранению распространенных проблем с типами ожидания.

Описание многих типов ожиданий и то, что они указывают, см. в таблице в разделе "Типы ожиданий".

Диагностика различий в планах выполнения запросов

Ниже приведены некоторые распространенные причины различий в планах запросов:

  • Различия размера данных или значений данных

    Используется ли одна и та же база данных на обоих серверах с использованием одной резервной копии базы данных? Изменены ли данные на одном сервере по сравнению с другим? Различия данных могут привести к разным планам запросов. Например, присоединение таблицы T1 (1000 строк) к таблице T2 (2000 000 строк) отличается от объединения таблицы T1 (100 строк) с таблицей T2 (2000 000 строк). Тип и скорость JOIN операции могут быть значительно разными.

  • Различия статистики

    Обновлены ли статистические данные в одной базе данных, а не на другой? Обновлены ли статистические данные с другой частотой выборки (например, 30% в сравнении с 100% полной выборки)? Убедитесь, что вы обновляете статистику на обеих сторонах с одинаковой частотой выборки.

  • Различия на уровне совместимости базы данных

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

    SELECT name, compatibility_level
    FROM sys.databases
    WHERE name = '<YourDatabase>'
    
  • Различия версий сервера и сборки

    Отличаются ли версии или сборки SQL Server между двумя серверами? Например, один сервер SQL Server версии 2014 и другой SQL Server версии 2016? Могут быть изменения продукта, которые могут привести к изменениям в выборе плана запроса. Убедитесь, что вы сравниваете ту же версию и сборку SQL Server.

    SELECT ServerProperty('ProductVersion')
    
  • Различия версий оценки кратности (CE)

    Проверьте, включен ли устаревший средство оценки кратности на уровне базы данных. Дополнительные сведения о CE см. в разделе "Оценка кратности" (SQL Server).

    SELECT name, value, is_value_default
    FROM sys.database_scoped_configurations
    WHERE name = 'LEGACY_CARDINALITY_ESTIMATION'
    
  • Включение/отключение исправлений/патчей для оптимизатора

    Если исправления оптимизатора запросов включены на одном сервере, но отключены на другом, можно создать разные планы запросов. Дополнительные сведения см. в статье о модели обслуживания оптимизатора запросов SQL Server.

    Чтобы получить состояние исправлений оптимизатора запросов, выполните следующий запрос:

    -- Check at server level for TF 4199
    DBCC TRACESTATUS (-1)
    -- Check at database level
    USE <YourDatabase>
    SELECT name, value, is_value_default 
    FROM sys.database_scoped_configurations
    WHERE name = 'QUERY_OPTIMIZER_HOTFIXES'
    
  • Различия флагов трассировки

    Некоторые флаги трассировки влияют на выбор плана запроса. Проверьте, включены ли флаги трассировки на одном сервере, но не включены на другом. Выполните следующий запрос на обоих серверах и сравните результаты:

    -- Check at server level for trace flags
    DBCC TRACESTATUS (-1)
    
  • Различия оборудования (количество ЦП, размер памяти)

    Чтобы получить сведения о оборудовании, выполните следующий запрос:

    SELECT cpu_count, physical_memory_kb/1024/1024 PhysicalMemory_GB 
    FROM sys.dm_os_sys_info
    
  • Различия оборудования в соответствии с оптимизатором запросов

    Проверьте OptimizerHardwareDependentProperties плана запроса и убедитесь, что различия в оборудовании считаются значительными для различных планов.

    WITH xmlnamespaces(DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')
    SELECT
      txt.text,
      t.OptHardw.value('@EstimatedAvailableMemoryGrant', 'INT') AS EstimatedAvailableMemoryGrant , 
      t.OptHardw.value('@EstimatedPagesCached', 'INT') AS EstimatedPagesCached, 
      t.OptHardw.value('@EstimatedAvailableDegreeOfParallelism', 'INT') AS EstimatedAvailDegreeOfParallelism,
      t.OptHardw.value('@MaxCompileMemory', 'INT') AS MaxCompileMemory
    FROM sys.dm_exec_cached_plans AS cp
    CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) AS qp
    CROSS APPLY qp.query_plan.nodes('//OptimizerHardwareDependentProperties') AS t(OptHardw)
    CROSS APPLY sys.dm_exec_sql_text (CP.plan_handle) txt
    WHERE text Like '%<Part of Your Query>%'
    
  • Время ожидания оптимизатора

    Существует ли проблема с временем ожидания оптимизатора? Оптимизатор запросов может остановить оценку параметров плана, если выполняемый запрос слишком сложный. Когда он останавливается, он выбирает план с наименьшей стоимостью, доступной в то время. Это может привести к произвольному выбору плана на одном сервере по сравнению с другим.

  • Параметры SET

    Некоторые параметры SET влияют на планирование, например SET ARITHABORT. Дополнительные сведения см. в разделе "Параметры SET".

  • Различия между подсказками запросов

    Использует ли один запрос подсказки для запросов, а другой нет? Проверьте текст запроса вручную, чтобы установить наличие подсказок запроса.

  • Планы, зависящие от параметров (вопрос параметрического анализа)

    Тестируете запрос с одинаковыми значениями параметров? Если нет, то вы можете начать там. Был ли план скомпилирован ранее на одном сервере на основе другого значения параметра? Проверьте два запроса, используя подсказку запроса RECOMPILE, чтобы убедиться, что не происходит повторного использования плана. Дополнительные сведения см. в разделе "Изучение и устранение проблем с учетом параметров".

  • Различные параметры базы данных/настройки конфигурации с ограниченными областями действия.

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

    -- On Server1 add a linked server to Server2 
    EXEC master.dbo.sp_addlinkedserver @server = N'Server2', @srvproduct=N'SQL Server'
    
    -- Run a join between the two servers to compare settings side by side
    SELECT 
       s1.name AS srv1_config_name, 
       s2.name AS srv2_config_name,
       s1.value_in_use AS srv1_value_in_use, 
       s2.value_in_use AS srv2_value_in_use, 
       Variance = CASE WHEN ISNULL(s1.value_in_use, '##') != ISNULL(s2.value_in_use,'##') THEN 'Different' ELSE '' END
    FROM sys.configurations s1 
    FULL OUTER JOIN [server2].master.sys.configurations s2 ON s1.name = s2.name
    
    
    SELECT 
       s1.name AS srv1_config_name,
       s2.name AS srv2_config_name,
       s1.value srv1_value_in_use,
       s2.value srv2_value_in_use,
       s1.is_value_default,
       s2.is_value_default,
       Variance = CASE WHEN ISNULL(s1.value, '##') != ISNULL(s2.value, '##') THEN 'Different' ELSE '' END
    FROM sys.database_scoped_configurations s1
    FULL OUTER JOIN [server2].master.sys.database_scoped_configurations s2 ON s1.name = s2.name
    
  • Руководства по планированию

    Используются ли плановые указания для запросов на одном сервере, но не на другом? Выполните следующий запрос, чтобы установить различия:

    SELECT * FROM sys.plan_guides