При профилировании базы данных я столкнулся с представлением, которое ссылается на некоторые недетерминированные функции, к которым обращаются 1000-2500 раз в минуту для каждого соединения в пуле этого приложения. Простое SELECT
представление дает следующий план выполнения:
Это выглядит как сложный план для представления, в котором менее тысячи строк, в которых один или два ряда могут меняться каждые несколько месяцев. Но это ухудшается со следующими другими соблюдениями:
- Вложенные представления являются недетерминированными, поэтому мы не можем их индексировать
- Каждое представление ссылается на несколько
UDF
s для построения строк - Каждый UDF содержит вложенные
UDF
s для получения ISO-кодов для локализованных языков. - Представления в стеке используют дополнительные строители строк, возвращаемые из
UDF
s в качествеJOIN
предикатов - Каждый стек представлений обрабатывается как таблица, что означает наличие
INSERT
/UPDATE
/DELETE
триггеров на каждом для записи в базовые таблицы - Эти триггеры взглядов использовать ,
CURSORS
чтоEXEC
хранимые процедуры , которые ссылаются на более из этих строк зданияUDF
s.
Мне это кажется довольно гнилым, но у меня всего несколько лет опыта работы с TSQL. Это тоже становится лучше!
Похоже, разработчик, который решил, что это отличная идея, сделал все это так, чтобы несколько сотен хранимых строк могли иметь перевод, основанный на строке, возвращенной из UDF
специфической для схемы схемы.
Вот одно из представлений в стеке, но все они одинаково плохи:
CREATE VIEW [UserWKStringI18N]
AS
SELECT b.WKType, b.WKIndex
, CASE
WHEN ISNULL(il.I18NID, N'') = N''
THEN id.I18NString
ELSE il.I18nString
END AS WKString
,CASE
WHEN ISNULL(il.I18NID, N'') = N''
THEN id.IETFLangCode
ELSE il.IETFLangCode
END AS IETFLangCode
,dbo.User3StringI18N_KeyValue(b.WKType, b.WKIndex, N'WKS') AS I18NID
,dbo.UserI18N_Session_Locale_Key() AS IETFSessionLangCode
,dbo.UserI18N_Database_Locale_Key() AS IETFDatabaseLangCode
FROM UserWKStringBASE b
LEFT OUTER JOIN User3StringI18N il
ON (
il.I18NID = dbo.User3StringI18N_KeyValue(b.WKType, b.WKIndex, N'WKS')
AND il.IETFLangCode = dbo.UserI18N_Session_Locale_Key()
)
LEFT OUTER JOIN User3StringI18N id
ON (
id.I18NID = dbo.User3StringI18N_KeyValue(b.WKType, b.WKIndex,N'WKS')
AND id.IETFLangCode = dbo.UserI18N_Database_Locale_Key()
)
GO
Вот почему UDF
s используются в качестве JOIN
предикатов. I18NID
Колонна формируется путем конкатенации:STRING + [ + ID + | + ID + ]
Во время их тестирования простой SELECT
из представления возвращает ~ 309 строк и требует 900-1400 мс для выполнения. Если я помещаю строки в другую таблицу и добавляю к ней индекс, тот же выбор возвращается через 20-75 мс.
Итак, короткая история (и я надеюсь, что вы оценили эту глупость), я хочу быть добрым самаритянином, перепроектировать и переписать это для 99% клиентов, использующих этот продукт, которые вообще не используют какую-либо локализацию. Ожидается, что конечные пользователи будут использовать [en-US]
локаль, даже если английский является вторым / третьим языком.
Поскольку это неофициальный взлом, я думаю о следующем:
- Создайте новую таблицу String, заполненную четко объединенным набором данных из исходных базовых таблиц.
- Индексируйте таблицу.
- Создание замены набора представлений верхнего уровня в стеке , которые включают в себя
NVARCHAR
иINT
столбцах дляWKType
иWKIndex
столбцов. - Измените несколько
UDF
s, которые ссылаются на эти представления, чтобы избежать преобразований типов в некоторых предикатах соединения (наша самая большая таблица аудита - 500-2000M строк и хранитINT
вNVARCHAR(4000)
столбце, который используется для объединения соWKIndex
столбцом (INT
).) - Схема привязки взглядов
- Добавьте несколько индексов к представлениям
- Перестройте триггеры в представлениях, используя заданную логику вместо курсоров.
Теперь мои актуальные вопросы:
- Есть ли лучший метод для обработки локализованных строк через представление?
- Какие существуют альтернативы для использования
UDF
в качестве заглушки? (Я могу написать конкретныйVIEW
для каждого владельца схемы и жестко закодировать язык, не полагаясь на различныеUDF
заглушки.) - Можно ли просто сделать эти представления детерминированными, полностью квалифицируя вложенные
UDF
s и затем связывая схемы стеками представления?
UDF
определение. Также обратитесь к пользовательским функциям T-SQL: хорошее, плохое и безобразноеОтветы:
Глядя на данный код, мы можем сказать,
Во-вторых, UDF не следует часто вызывать для одного и того же столбца. Здесь он вызывается один раз в выбранном
и второй раз за вступление
Можно генерировать значения во временной таблице или использовать CTE (Common Table Expression), чтобы получить эти значения в первую очередь до того, как произойдет соединение.
Я создал образец USP, который обеспечит некоторые улучшения:
Пожалуйста, попробуйте это
источник