різниця в планах виконання на сервері UAT та PROD


39

Я хочу зрозуміти, чому була б така величезна різниця у виконанні одного і того ж запиту на UAT (працює за 3 сек) проти PROD (запустити за 23 секунди).

І UAT, і PROD мають точно дані та індекси.

ПИТАННЯ:

set statistics io on;
set statistics time on;

SELECT CONF_NO,
       'DE',
       'Duplicate Email Address ''' + RTRIM(EMAIL_ADDRESS) + ''' in Maintenance',
       CONF_TARGET_NO
FROM   CONF_TARGET ct
WHERE  CONF_NO = 161
       AND LEFT(INTERNET_USER_ID, 6) != 'ICONF-'
       AND ( ( REGISTRATION_TYPE = 'I'
               AND (SELECT COUNT(1)
                    FROM   PORTFOLIO
                    WHERE  EMAIL_ADDRESS = ct.EMAIL_ADDRESS
                           AND DEACTIVATED_YN = 'N') > 1 )
              OR ( REGISTRATION_TYPE = 'K'
                   AND (SELECT COUNT(1)
                        FROM   CAPITAL_MARKET
                        WHERE  EMAIL_ADDRESS = ct.EMAIL_ADDRESS
                               AND DEACTIVATED_YN = 'N') > 1 ) ) 

ON UAT:

SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 11 ms, elapsed time = 11 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

(3 row(s) affected)
Table 'Worktable'. Scan count 256, logical reads 1304616, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'PORTFOLIO'. Scan count 1, logical reads 84761, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'CAPITAL_MARKET'. Scan count 256, logical reads 9472, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'CONF_TARGET'. Scan count 1, logical reads 100, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 2418 ms,  elapsed time = 2442 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

введіть тут опис зображення

ПРО PROD:

SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

(3 row(s) affected)
Table 'PORTFOLIO'. Scan count 256, logical reads 21698816, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'CAPITAL_MARKET'. Scan count 256, logical reads 9472, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'CONF_TARGET'. Scan count 1, logical reads 100, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 23937 ms,  elapsed time = 23935 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

введіть тут опис зображення

Зауважте, що в PROD запит пропонує відсутність індексу, і це корисно, як я перевірив, але це не суть дискусії.

Я просто хочу зрозуміти, що: ON UAT - чому сервер sql створює таблицю робочих, а в PROD - це не так? Він створює котушку таблиці на UAT, а не на PROD. Крім того, чому на UAT vs PROD такі часи виконання так різні?

Примітка :

Я використовую sql-сервер 2008 R2 RTM на обох серверах (досить скоро збирається виправити з останніми SP).

UAT: Максимальна пам'ять 8 Гб. MaxDop, спорідненість процесора та максимальна кількість робочих ниток - 0.

Logical to Physical Processor Map:
*-------  Physical Processor 0
-*------  Physical Processor 1
--*-----  Physical Processor 2
---*----  Physical Processor 3
----*---  Physical Processor 4
-----*--  Physical Processor 5
------*-  Physical Processor 6
-------*  Physical Processor 7

Logical Processor to Socket Map:
****----  Socket 0
----****  Socket 1

Logical Processor to NUMA Node Map:
********  NUMA Node 0

ПРОД: максимальна пам'ять 60 Гб. MaxDop, спорідненість процесора та максимальна кількість робочих ниток - 0.

Logical to Physical Processor Map:
**--------------  Physical Processor 0 (Hyperthreaded)
--**------------  Physical Processor 1 (Hyperthreaded)
----**----------  Physical Processor 2 (Hyperthreaded)
------**--------  Physical Processor 3 (Hyperthreaded)
--------**------  Physical Processor 4 (Hyperthreaded)
----------**----  Physical Processor 5 (Hyperthreaded)
------------**--  Physical Processor 6 (Hyperthreaded)
--------------**  Physical Processor 7 (Hyperthreaded)

Logical Processor to Socket Map:
********--------  Socket 0
--------********  Socket 1

Logical Processor to NUMA Node Map:
********--------  NUMA Node 0
--------********  NUMA Node 1

ОНОВЛЕННЯ:

План виконання UAT XML:

http://pastebin.com/z0PWvw8m

План виконання програми XML:

http://pastebin.com/GWTY16YY

План виконання UAT XML - із планом, створеним для PROD:

http://pastebin.com/74u3Ntr0

Конфігурація сервера:

PROD: PowerEdge R720xd - процесор Intel (R) Xeon (R) E5-2637 v2 при 3,50 ГГц.

UAT: PowerEdge 2950 - Intel (R) Xeon (R) процесор X5460 при 3,16 ГГц

Я розмістив повідомлення на сайті answer.sqlperformance.com


ОНОВЛЕННЯ:

Дякуємо @swasheck за пропозицію

Змінюючи максимальну пам'ять PROD з 60 ГБ на 7680 МБ, я можу генерувати той же план у PROD. Запит виконується в той же час, що і UAT.

Тепер мені потрібно зрозуміти - ЧОМУ? Також цим я не зможу виправдати цей сервер-монстр замінити старий сервер!

Відповіді:


43

Потенційний розмір буферного пулу різним чином впливає на вибір плану оптимізатором запитів. Наскільки я знаю, гіпер-нарізка не впливає на вибір плану (хоча кількість потенційно доступних планувальників, безумовно, може).

Пам'ять робочої області

Для планів, що містять ітератори, що споживають пам'ять, такі як сорти та хеші, розмір буферного пулу (серед іншого) визначає максимальний обсяг пам'яті, який може бути доступний запиту під час виконання.

У SQL Server 2012 (усі версії) про це число повідомляється у кореневому вузлі плану запитів у Optimizer Hardware Dependenciesрозділі, показаному як Estimated Available Memory Grant. Версії до 2012 року не показують цю кількість у шоу-плані.

Приблизний доступний розмір пам'яті - це вхід до моделі витрат, що використовується оптимізатором запитів. Як результат, альтернатива плану, яка вимагає великої операції сортування або хешування, скоріше буде обрана на машині з великим налаштуванням буферного пулу, ніж на машині з нижчим параметром. Для установок з дуже великим обсягом пам’яті модель витрат може зайти занадто далеко з таким мисленням - вибираючи плани з дуже великими видами або хешами, де альтернативна стратегія буде кращою ( KB2413549 - Використання великої кількості пам'яті може призвести до неефективний план у SQL Server - TF2335 ).

Надання пам’яті робочої області не є фактором у вашому випадку, але це щось, про що варто знати.

Доступ до даних

Потенційний розмір буферного пулу також впливає на модель витрат оптимізатора на доступ до даних. Одне з припущень, зроблених у моделі, полягає в тому, що кожен запит починається з холодного кешу - тому перший доступ до сторінки передбачається мати фізичний ввід / вивід. Модель намагається врахувати шанс того, що повторний доступ буде надходити з кешу, фактор, що залежить від потенційного розміру буферного пулу серед іншого.

Сканування кластерних індексів у планах запитів, показаних у питанні, є одним із прикладів повторного доступу; скани перемотаються (повторюються, без зміни корельованого параметра) для кожної ітерації вкладених циклів напівз'єднання. Зовнішній вхід до напівз'єднання оцінює 28,7874 рядків, а властивості плану запитів для цих сканувань показують, що оцінюється перемотування назад у 27,7874.

Знову ж таки, лише у SQL Server 2012 кореневий ітератор плану показує номер Estimated Pages Cachedу Optimizer Hardware Dependenciesрозділі. Цей номер повідомляє про один із входів до алгоритму калькулювання, який враховує можливість повторного доступу до сторінки, що надходить із кешу.

Ефект полягає в тому, що установка з більш високим налаштованим максимальним розміром буферного пулу, як правило, знизить вартість сканувань (або шукає), які читають одні й ті самі сторінки не один раз більше, ніж установка з меншим максимальним розміром пулу буфера.

У простих планах зниження витрат на сканування перемотування можна побачити, порівнюючи (estimated number of executions) * (estimated CPU + estimated I/O)з передбачуваною вартістю оператора, яка буде нижчою. Розрахунок складніший у прикладних планах через ефект напівз'єднання та об'єднання.

Тим не менш, плани у питанні, як видається, показують випадок, коли вибір між повторенням сканування та створенням тимчасового індексу є досить тонко збалансованим. На машині з більшим буферним пулом повторення сканування коштує трохи нижче, ніж створення індексу. На машині з меншим буферним пулом вартість сканування зменшується на меншу суму, тобто оптимізатор виглядає план котушки індексу трохи дешевше.

Вибір плану

Модель витрат оптимізатора робить ряд припущень і містить велику кількість детальних розрахунків. Не завжди (або навіть зазвичай) можливо дотримуватися всіх деталей, оскільки не всі числа, які нам знадобляться, піддаються впливу, і алгоритми можуть змінюватися між випусками. Зокрема, формула масштабування, застосована для врахування шансу зустрітися з кешованою сторінкою, недостатньо відома.

Більш суттєвим у цьому конкретному випадку вибір плану оптимізатора в будь-якому випадку базується на неправильних числах. Орієнтовна кількість рядків з кластерного індексу шукає 28,7874, тоді як 256 рядків зустрічаються під час виконання - майже на порядок. Ми не можемо безпосередньо побачити інформацію, яку має оптимізатор щодо очікуваного розподілу значень у межах цих 28,7874 рядків, але, ймовірно, це буде жахливо помилятися.

Коли оцінки невірні, вибір плану та виконання часу по суті не є кращим за випадковість. План з індексною котушкою виявляється краще, ніж повторення сканування, але цілком неправильно думати, що збільшення розміру буферного пулу було причиною аномалії.

Якщо оптимізатор має правильну інформацію, шанси набагато краще, що він створить гідний план виконання. Екземпляр з більшою кількістю пам’яті, як правило, краще працює на навантаженні, ніж інший екземпляр з меншою пам’яттю, але немає гарантій, особливо коли вибір плану базується на невірних даних.

Обидва екземпляри по-своєму запропонували відсутній індекс. Один повідомив про явний відсутній індекс, а інший використав індексну котушку з тими ж характеристиками. Якщо індекс забезпечує хорошу ефективність та стабільність плану, цього може бути достатньо. Моє бажання було б також переписати запит, але це, мабуть, інша історія.


18

Пол Уайт чудово пояснив причину - поведінку сервера sql під час роботи на серверах з більшою кількістю пам'яті.

Також величезне спасибі @swasheck за те, що вперше помітили проблему.

Відкрив справу з мікрософт і нижче - те, що було запропоновано.

Проблема вирішується за допомогою прапора трассирування T2335 в якості параметра запуску.

KB2413549 - Використання великих обсягів пам'яті може призвести до неефективного плану в SQL Server описує це більш докладно.

Цей прапор трасування призведе до того, що SQL Server генерує план, більш консервативний з точки зору споживання пам'яті при виконанні запиту. Це не обмежує кількість пам'яті, яку може використовувати SQL Server. Пам'ять, налаштована для SQL Server, як і раніше використовуватиме кеш даних, виконання запитів та інших споживачів. Будь ласка, переконайтесь, що ви ретельно протестуєте цю опцію, перш ніж передати її у виробниче середовище.


13

Максимальні параметри пам'яті та гіперточення можуть впливати на вибір плану.

Крім того, я помічаю, що ваші параметри "встановити" різні в кожному середовищі:

Заявки набори щодо UAT:

ANSI_NULLS="true" 
ANSI_PADDING="true" 
ANSI_WARNINGS="true" 
ARITHABORT="true" 
CONCAT_NULL_YIELDS_NULL="true" 
NUMERIC_ROUNDABORT="false" 
QUOTED_IDENTIFIER="true" 

StatementSetOptions про Prod:

ANSI_NULLS="true" 
ANSI_PADDING="true" 
ANSI_WARNINGS="true" 
ARITHABORT="false" 
CONCAT_NULL_YIELDS_NULL="true"
NUMERIC_ROUNDABORT="false"
QUOTED_IDENTIFIER="true" 

SQL може генерувати різні плани на основі параметрів SET. Це часто трапляється, якщо ви захоплюєте план з різних сесій SSMS або з різних застосувань програми.

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


2
Ви вірно стверджуєте, що Max Memory і Hyperthreading можуть впливати на кеш-план, але я хочу детально знати, що і чому сталося. Вдячний за вашу відповідь.
Кін Шах

2
Як сказала Аманда, якщо параметри SET відрізняються від ARITHABORT, ви можете подивитися на dba.stackexchange.com/questions/9840/…
ARA
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.