У меня есть таблица ItemValue, полная данных на сервере SQL 2005, работающем в режиме совместимости с 2000, которая выглядит примерно так (это таблица пользовательских значений):
ID ItemCode FieldID Value
-- ---------- ------- ------
1 abc123 1 D
2 abc123 2 287.23
4 xyz789 1 A
5 xyz789 2 3782.23
6 xyz789 3 23
7 mno456 1 W
9 mno456 3 45
... and so on.
FieldID берется из таблицы ItemField:
ID FieldNumber DataFormatID Description ...
-- ----------- ------------ -----------
1 1 1 Weight class
2 2 4 Cost
3 3 3 Another made up description
. . x xxx
. . x xxx
. . x xxx
x 91 (we have 91 user-defined fields)
Поскольку я не могу PIVOT в режиме 2000, мы застряли в построении уродливого запроса с использованием CASE и GROUP BY, чтобы данные выглядели так, как они должны выглядеть для некоторых устаревших приложений, а именно:
ItemNumber Field1 Field2 Field3 .... Field51
---------- ------ ------- ------
abc123 D 287.23 NULL
xyz789 A 3782.23 23
mno456 W NULL 45
Как видите, нам нужна эта таблица только для отображения значений до 51-го UDF. Вот запрос:
SELECT
iv.ItemNumber,
,MAX(CASE WHEN f.FieldNumber = 1 THEN iv.[Value] ELSE NULL END) [Field1]
,MAX(CASE WHEN f.FieldNumber = 2 THEN iv.[Value] ELSE NULL END) [Field2]
,MAX(CASE WHEN f.FieldNumber = 3 THEN iv.[Value] ELSE NULL END) [Field3]
...
,MAX(CASE WHEN f.FieldNumber = 51 THEN iv.[Value] ELSE NULL END) [Field51]
FROM ItemField f
LEFT JOIN ItemValue iv ON f.ID = iv.FieldID
WHERE f.FieldNumber <= 51
GROUP BY iv.ItemNumber
Когда ограничение FieldNumber равно ‹= 51, план выполнения выглядит примерно так:
SELECT <== Computer Scalar <== Stream Aggregate <== Sort (Cost: 70%) <== Hash Match <== (Clustered Index Seek && Table Scan)
и это быстро! Я могу извлечь более 100 000 записей примерно за секунду, что соответствует нашим потребностям.
Однако, если у нас было больше пользовательских функций и я изменил ограничение на что-то выше 66 (да, я тестировал их по одному) или если я полностью удалю его, я потеряю Сортировку в плане выполнения и он заменяется целой кучей блоков Parallelism, которые собирают, перераспределяют и распределяют потоки, и все это работает медленно (30 секунд даже для одной записи).
FieldNumber имеет кластеризованный уникальный индекс и является частью составного первичного ключа со столбцом ID (некластеризованный индекс) в таблице ItemField. . Столбцы ID и ItemNumber таблицы ItemValue составляют PK, а для ItemNumber колонка.
Какова причина этого? Почему изменение моего простого целочисленного ограничения меняет весь план выполнения?
И если вы согласны... Что бы вы сделали по-другому? Через пару месяцев запланировано обновление SQL, но мне нужно решить эту проблему до этого.