Добавление: SQL Server 2012 показывает некоторую улучшенную производительность в этой области, но, похоже, не решает конкретные проблемы, отмеченные ниже. это
должно быть исправлено в следующей основной версии после
SQL Server 2012!
Ваш план показывает, что отдельные вставки используют параметризованные процедуры (возможно, автоматически параметризованные), поэтому время разбора / компиляции для них должно быть минимальным.
Я подумал, что немного подробнее расскажу об этом, поэтому настроил цикл ( script ) и попытался отрегулировать количество предложений 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
Таким образом, удаление имен в трассировке стека, кажется, тратит много времени на сравнение строк.
В этой статье базы знаний указано, что DeriveNormalizedGroupProperties
связано с тем, что раньше называлось нормализацией стадией обработки запросов
Этот этап теперь называется связыванием или алгебрированием, и он берет дерево синтаксического анализа выражений, выведенное на предыдущем этапе синтаксического анализа, и выводит дерево алгебраических выражений (дерево обработчика запросов), чтобы перейти к оптимизации (в данном случае тривиальной оптимизации плана) [ссылка] .
Я попробовал еще один эксперимент ( Script ), который должен был повторно запустить исходный тест, но с рассмотрением трех разных случаев.
- Имя и фамилия Строки длиной 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
) и не делитсянулевая ошибка повышена.Если дубликаты добавляются в таблицу, то оператор сортировки отображает два порядка по столбцам и возникает ожидаемая ошибка.