По-разному выполняются запросы в SQL 2005 и SQL 2008R2

9

В моем офисе у нас довольно уродливый запрос, но он довольно хорошо работает как в рабочей среде, так и в среде разработки (20 с и 4 с соответственно). Однако в нашей тестовой среде это занимает более 4 часов. SQL2005 (+ последние исправления) запущен в производстве и разработке. SQL2008R2 работает в тестировании.

Я взглянул на план запросов, и он показывает, что SQL2008R2 использует TempDB, используя Table Spool (ленивый спул) для хранения возвращаемых строк со связанного сервера. Следующий шаг показывает, что Nested Loops (левое анти-полусоединение) истощает 96,3% запроса. Линия между двумя операторами составляет 5 398 МБ!

План запроса для SQL 2005 не показывает использование базы данных tempdb и не использует левое анти-полусоединение.

Ниже приведен очищенный код и план выполнения сверху 2005 года, а 2008R2 снизу.

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

Нужно ли мне смотреть на базовое оборудование, так как версия 2008R2 использует базу данных tempdb, мне нужно взглянуть на то, как оптимизировать использование этого?

Есть ли лучший способ написать запрос?

Спасибо за помощь.

    INSERT INTO Table1_GroupLock (iGroupID, dLockedDate)
SELECT 
 Table1.iGroupID,
 GETDATE()
FROM Table1
WHERE 
 NOT EXISTS (
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE 
   (
    Alias2.FirstName + Alias2.LastName = dbo.fnRemoveNonLetter(Table1.FullName)
    AND NOT dbo.fnRemoveNonLetter(Table1.FullName) IS NULL
    AND NOT Alias2.FirstName IS NULL 
    AND NOT Alias2.LastName  IS NULL
   ) OR (
    Alias2.FamilyName = dbo.fnRemoveNonLetter(Table1.FamilyName)
    AND Alias2.Child1Name = dbo.fnRemoveNonLetter(Table1.Child1Name)
    AND NOT dbo.fnRemoveNonLetter(Table1.FamilyName) IS NULL
    AND NOT dbo.fnRemoveNonLetter(Table1.Child1Name) IS NULL
    AND NOT Alias2.Familyname IS NULL
    AND NOT Alias2.Child1Name IS NULL
   ) OR (
    Alias2.StepFamilyName = dbo.fnRemoveNonLetter(Table1.StepFamilyName)
    AND Alias2.StepFamilyNameChild1 = dbo.fnRemoveNonLetter(Table1.StepFamilyNameChild2)
    AND NOT Alias2.StepFamilyName IS NULL
    AND NOT Alias2.StepFamilyNameChild1 IS NULL
    AND NOT dbo.fnRemoveNonLetter(Table1.StepFamilyName) IS NULL
    AND NOT dbo.fnRemoveNonLetter(Table1.StepFamilyNameChild2) IS NULL
   )  
 ) AND NOT EXISTS (
  SELECT 1
  FROM Table3
  INNER JOIN Table4
   ON Table4.FirstNameType = Table3.FirstNameType 
  INNER JOIN table5
   ON table5.LastNameType = Table3.LastNameType 
  WHERE 
   Table3.iGroupID = Table1.iGroupID
   AND Table3.bIsClosed = 0
   AND Table4.sNameTypeConstant = 'new_lastname'
   AND table5.sFirstNameConstant = 'new_firstname'
 )

SQL-2005


SQL2008R2

:: EDIT :: Выполнял запрос из другого экземпляра SQL2005, в основном того же плана выполнения, что и «хороший». Все еще не уверен, как две версии 2005 работают лучше на связанном сервере 2008R2, чем экземпляры 2008R2 для экземпляров 2008R2.

Хотя я не отрицаю, что код мог использовать какую-то работу, если бы это был код, являющийся проблемой, разве я не увидел бы одинаковые планы exec во всех моих испытаниях? Независимо от версии SQL?

:: РЕДАКТИРОВАТЬ :: Я применил SP1 и CU3 к обоим экземплярам 2008R2, но все еще не играли в кости. Я специально установил коллокацию на связанном сервере, без игры в кости. Я специально установил разрешения моего acct пользователя для sysadmin в обоих случаях, без игры в кости. Я также вспомнил о своих внутренних проблемах и устранении неполадок в sql server 2008, посмотрим, смогу ли я как-нибудь это отследить.

Спасибо всем за помощь и советы.

:: РЕДАКТИРОВАТЬ :: Я сделал различные изменения разрешений для связанного сервера. Я использовал SQL логины, доменные логины, я выдавал себя за других пользователей, я использовал опцию «be made with this context». Я создал пользователей на обеих сторонах связанного сервера, которые имеют права sysadmin на сервере. У меня нет идей.

Я все еще хотел бы знать, почему SQL2005 выполняет запрос так резко отличается от SQL2008R2. Если бы это был неправильный запрос, я бы увидел время выполнения 4 часа на SQL2005 и SQL2008R2.

битпоток
источник

Ответы:

5

Я бы хотел, чтобы вы переработали запрос.

У вас есть проблемы с sargability, и вы даже используете там скалярные вызовы функций, что также повредит запросу. Возможно, вы захотите создать вычисляемый столбец FullName в Таблице 2 и поместить в него индекс, убедившись, что ваш индекс INCLUDEs FirstName и LastName. Вы также должны добавить индексы, которые помогают другим

Кроме того, создайте встроенную табличную функцию для выполнения функции «RemoveNonLetter» и доработайте свой запрос, чтобы использовать его, возможно, используя APPLY, как я это сделал здесь.

И определенно проверьте эту ошибку, на которую ссылается ответ Пола .

INSERT INTO Table1_GroupLock (iGroupID, dLockedDate)
SELECT 
 Table1.iGroupID,
 GETDATE()
FROM Table1
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.FullName)) AS fn (FullName)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.FamilyName)) AS famn (FamilyName)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.Child1Name)) AS c1n (Child1Name)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.StepFamilyName)) AS sfn (StepFamilyName)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.StepFamilyNameChild2)) AS sfnc2 (StepFamilyNameChild2)
WHERE 
 NOT EXISTS (
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE Alias2.FullName = fn.FullName
  UNION ALL
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE Alias2.FamilyName = famn.FamilyName AND Alias2.Child1Name = c1n.Child1Name
  UNION ALL
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE Alias2.StepFamilyName = sfn.StepFamilyName AND Alias2.StepFamilyNameChild1 = sfnc2.StepFamilyNameChild2
 ) 
 AND NOT EXISTS (
  SELECT 1
  FROM Table3
  INNER JOIN Table4
   ON Table4.FirstNameType = Table3.FirstNameType 
  INNER JOIN table5
   ON table5.LastNameType = Table3.LastNameType 
  WHERE 
   Table3.iGroupID = Table1.iGroupID
   AND Table3.bIsClosed = 0
   AND Table4.sNameTypeConstant = 'new_lastname'
   AND table5.sFirstNameConstant = 'new_firstname'
 )
;
Роб Фарли
источник
6

В добавление к предыдущим ответам, причиной регрессии плана может быть известная ошибка оценки количества элементов, когда план включает в себя Anti Semi Join. См. KB 2222998.

Предполагая, что план 2005 года обеспечил приемлемую производительность, вы можете обнаружить, что перевод сервера на версию, включающую это исправление (и включение TF4199 для его активации), вернет вас к «хорошему» плану.

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

Пол Уайт 9
источник
5

Я бы предположил, что удаленные данные помещаются в буфер локально, потому что один из

  1. Настройки связанного сервера (например, параметры сортировки) не совпадают
  2. Локальное сопоставление отличается от удаленного, несмотря на настройки связанного сервера
  3. Запрос не может работать правильно удаленно из-за разрешений

Для пункта 1 см. Sp_serveroption
And для пункта 2, но также проверьте параметры сопоставления сервер / дБ.

Для пункта 3, посмотрите это из Линчи Ши:

Вы просите SQL Server обрабатывать все данные локально, в соответствии с моим ответом здесь: Влияние на производительность при использовании OPENQUERY в представлении

редактировать

При втором взгляде я вижу 2 удаленных вызова по «хорошему» плану, а не один. Это подтверждает то, что я говорю здесь

ГБН
источник
Извините за долгую задержку. 1: я проверил настройки связанного сервера, они одинаковые 2: я также проверил и неявно установил параметры сопоставления свойств связанного сервера для удаленного сервера. 3: контекст безопасности я все еще работаю над проведением A / B-тестирования. Я все еще спотыкаюсь о логике, лежащей в основе совершенно разных планов исполнительной власти. От сервера R2 до сервера R2 он только запускает select (тянет более 150 тыс. Строк), а затем выполняет соединения. Где, как с 2005 по R2, он делает выбор и присоединяется к удаленному серверу. Контекст безопасности для обоих сценариев одинаков.
RateControl
3

+1 в разделе Попытка перезаписи комментария к запросу от источника данных.

Мне также интересно, сталкиваетесь ли вы с проблемой разрешений на стороне связанного сервера, ведущей к этому замедлению. Я писал о замедлении работы этого связанного сервера некоторое время назад. Может быть, стоит проверить перми (это сервер, связанный с SQL? Или это другая СУБД? Если последняя, ​​то вы все равно не получите хорошую статистику)

У вас есть SQL Server 2005 в тестовой среде, чтобы попробовать этот запрос и исключить среду?

Вы восстановили статистику после обновления?

Майк Уолш
источник
3

С этим сравнением столько проблем ... Я просто не знаю, с чего начать.

  1. Получите точные спецификации для ваших производственных и испытательных машин.

  2. Определите сетевые ссылки между различными связанными серверами в обеих средах. Они одинаковой скорости? Находятся ли серверы рядом друг с другом в обеих средах?

  3. Можно ли вообще переписать запрос, чтобы НЕ использовать связанные серверы? Объединение таблиц между серверами делает вас уязвимым для изменений топологии, и в большинстве случаев это ужасно медленно.

  4. Использование NOT и OR обычно приводит к полному сканированию таблицы. Попробуйте переписать запрос.

datagod
источник