Доповнення: SQL Server 2012 демонструє деякі покращені показники роботи в цій галузі, але, схоже, не вирішує конкретні проблеми, зазначені нижче. Це, мабуть, має бути виправлено у наступній великій версії після
SQL Server 2012!
У вашому плані показано, що окремі вставки використовують параметризовані процедури (можливо, автоматичні параметри), тому час розбору / компіляції для них повинен бути мінімальним.
Я подумав, що я трохи більше задумаюся над цим, хоча так встановив цикл ( скрипт ) і спробував скоригувати кількість VALUES
пропозицій і записати час компіляції.
Потім я розділив час компіляції на кількість рядків, щоб отримати середній час компіляції за пропозицією. Результати нижче
До 250 VALUES
представлених пунктів час складання / кількість пунктів має незначну тенденцію до зростання, але нічого надто драматичного.
Але потім відбувається раптова зміна.
Цей розділ даних показано нижче.
+------+----------------+-------------+---------------+---------------+
| Rows | CachedPlanSize | CompileTime | CompileMemory | Duration/Rows |
+------+----------------+-------------+---------------+---------------+
| 245 | 528 | 41 | 2400 | 0.167346939 |
| 246 | 528 | 40 | 2416 | 0.162601626 |
| 247 | 528 | 38 | 2416 | 0.153846154 |
| 248 | 528 | 39 | 2432 | 0.157258065 |
| 249 | 528 | 39 | 2432 | 0.156626506 |
| 250 | 528 | 40 | 2448 | 0.16 |
| 251 | 400 | 273 | 3488 | 1.087649402 |
| 252 | 400 | 274 | 3496 | 1.087301587 |
| 253 | 400 | 282 | 3520 | 1.114624506 |
| 254 | 408 | 279 | 3544 | 1.098425197 |
| 255 | 408 | 290 | 3552 | 1.137254902 |
+------+----------------+-------------+---------------+---------------+
Розмір кешованого плану, який лінійно зростає, раптово падає, але CompileTime збільшується в 7 разів, а CompileMemory вистрілює вгору. Це точка відрізку між планом, який є автоматичним параметризованим (з 1000 параметрами) та не параметризованим. Згодом це здається лінійно менш ефективним (з точки зору кількості опрацьованих пропозицій за певний час).
Не впевнений, чому це повинно бути. Імовірно, при складанні плану для конкретних буквальних значень він повинен виконувати деяку діяльність, яка не масштабується лінійно (наприклад, сортування).
Схоже, це не впливає на розмір плану кешованих запитів, коли я спробував запит, що складається повністю з повторюваних рядків, і не впливає на порядок виведення таблиці констант (і, як ви вставляєте в сортування часу, витраченого на купу. все одно було б безглуздо, навіть якби це було).
Більше того, якщо кластерний індекс додається до таблиці, план все ще показує чіткий крок сортування, тому він, схоже, не сортує під час компіляції, щоб уникнути сортування під час виконання.
Я спробував розглянути це на відладчику, але загальнодоступні символи для моєї версії SQL Server 2008 здаються недоступними, тому замість цього мені довелося подивитися на еквівалентну UNION ALL
конструкцію в SQL Server 2005.
Типовий слід стека нижче
sqlservr.exe!FastDBCSToUnicode() + 0xac bytes
sqlservr.exe!nls_sqlhilo() + 0x35 bytes
sqlservr.exe!CXVariant::CmpCompareStr() + 0x2b bytes
sqlservr.exe!CXVariantPerformCompare<167,167>::Compare() + 0x18 bytes
sqlservr.exe!CXVariant::CmpCompare() + 0x11f67d bytes
sqlservr.exe!CConstraintItvl::PcnstrItvlUnion() + 0xe2 bytes
sqlservr.exe!CConstraintProp::PcnstrUnion() + 0x35e bytes
sqlservr.exe!CLogOp_BaseSetOp::PcnstrDerive() + 0x11a bytes
sqlservr.exe!CLogOpArg::PcnstrDeriveHandler() + 0x18f bytes
sqlservr.exe!CLogOpArg::DeriveGroupProperties() + 0xa9 bytes
sqlservr.exe!COpArg::DeriveNormalizedGroupProperties() + 0x40 bytes
sqlservr.exe!COptExpr::DeriveGroupProperties() + 0x18a bytes
sqlservr.exe!COptExpr::DeriveGroupProperties() + 0x146 bytes
sqlservr.exe!COptExpr::DeriveGroupProperties() + 0x146 bytes
sqlservr.exe!COptExpr::DeriveGroupProperties() + 0x146 bytes
sqlservr.exe!CQuery::PqoBuild() + 0x3cb bytes
sqlservr.exe!CStmtQuery::InitQuery() + 0x167 bytes
sqlservr.exe!CStmtDML::InitNormal() + 0xf0 bytes
sqlservr.exe!CStmtDML::Init() + 0x1b bytes
sqlservr.exe!CCompPlan::FCompileStep() + 0x176 bytes
sqlservr.exe!CSQLSource::FCompile() + 0x741 bytes
sqlservr.exe!CSQLSource::FCompWrapper() + 0x922be bytes
sqlservr.exe!CSQLSource::Transform() + 0x120431 bytes
sqlservr.exe!CSQLSource::Compile() + 0x2ff bytes
Таким чином, відмінюючи імена у сліді стека, схоже, витрачається багато часу на порівняння рядків.
Ця стаття KB вказує, що DeriveNormalizedGroupProperties
пов'язано з тим, що раніше називалося етапом нормалізації обробки запитів
Цей етап тепер називається зв'язуючим або алгебризуючим, і він бере висновок дерева розбору виразів з попереднього етапу розбору та виводить алгебризоване дерево вираження (дерево процесора запитів), щоб перейти до оптимізації (в цьому випадку тривіальна оптимізація плану) [ref] .
Я спробував ще один експеримент ( сценарій ), який повинен був повторно виконати оригінальний тест, але розглядаючи три різні випадки.
- Рядки з ім'ям та прізвищем довжиною 10 символів без дублікатів.
- Рядки з ім'ям та прізвищем довжиною 50 символів без дублікатів.
- Рядки з ім'ям та прізвищем довжиною 10 символів із усіма дублікатами.
Чітко видно, що чим довші струни, тим гірші речі стають, і що, навпаки, чим більше копій, тим краще діють речі. Як раніше згадані дублікати не впливають на розмір кешованого плану, тому я припускаю, що при конструюванні алгебризованого дерева експресії повинен бути процес ідентифікації дублікатів.
Редагувати
Одне місце, де використовується ця інформація, показане тут @Lieven
SELECT *
FROM (VALUES ('Lieven1', 1),
('Lieven2', 2),
('Lieven3', 3))Test (name, ID)
ORDER BY name, 1/ (ID - ID)
Оскільки під час компіляції він може визначити, що Name
стовпець не має дублікатів, він пропускає впорядкування за вторинним 1/ (ID - ID)
виразом під час виконання (сортування в плані має лише один ORDER BY
стовпець), і жодна помилка поділу на нуль не виникає. Якщо дублікати додаються до таблиці, то оператор сортування показує два порядки за стовпцями і очікувана помилка підвищується.