Podczas profilowania bazy danych natknąłem się na widok odwołujący się do niektórych niedeterministycznych funkcji, do których dostęp uzyskuje się 1000–2500 razy na minutę dla każdego połączenia w puli tej aplikacji. Prosty SELECTz widoku daje następujący plan wykonania:
To wydaje się być złożonym planem dla widoku, który ma mniej niż tysiąc wierszy, w których rząd lub dwa zmieniają się co kilka miesięcy. Ale pogarsza się z następującymi innymi obserwacjami:
- Widoki zagnieżdżone są niedeterministyczne, więc nie możemy ich indeksować
- Każdy widok odwołuje się do wielu
UDFs, aby zbudować ciągi - Każdy UDF zawiera zagnieżdżone
UDFs, aby uzyskać kody ISO dla zlokalizowanych języków - Widoki na stosie wykorzystują dodatkowe konstruktory ciągów zwrócone zs
UDFjakoJOINpredykaty - Każdy stos widoków jest traktowany jak tabela, co oznacza, że na każdym są
INSERT/UPDATE/DELETEwyzwalacze do zapisu do tabel bazowych - Te wyzwalacze na widokach używać
CURSORS, żeEXECprocedury stosowane przez odniesienie więcej z nich ciąg budynek przechowywaneUDFs.
Wydaje mi się to dość zepsute, ale mam tylko kilka lat doświadczenia z TSQL. To też staje się lepsze!
Wygląda na to, że programista, który zdecydował, że to świetny pomysł, zrobił to wszystko, aby kilkaset zapisanych ciągów mogło mieć tłumaczenie na podstawie ciągu zwróconego z określonego UDFschematu.
Oto jeden z widoków na stosie, ale wszystkie są równie złe:
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
Oto dlaczego UDFsą używane jako JOINpredykaty. I18NIDKolumna jest utworzona przez złączenie:STRING + [ + ID + | + ID + ]
Podczas testowania, prosty SELECTz widoku zwraca ~ 309 wierszy i zajmuje 900-1400 ms do wykonania. Jeśli zrzucę ciągi znaków do innej tabeli i uderzę w nią indeksem, ten sam wybór zostanie zwrócony za 20-75 ms.
Krótko mówiąc (i mam nadzieję, że doceniliście trochę tej głupoty) Chcę być dobrym Samarytaninem i przeprojektować i napisać to dla 99% klientów korzystających z tego produktu, którzy w ogóle nie używają żadnej lokalizacji - - użytkownicy końcowi powinni korzystać z [en-US]ustawień regionalnych, nawet jeśli angielski jest językiem 2/3.
Ponieważ jest to nieoficjalny hack, myślę o następujących rzeczach:
- Utwórz nową tabelę ciągów wypełnioną czysto połączonym zestawem danych z oryginalnych tabel podstawowych
- Indeksuj tabelę.
- Utwórz zestaw zastępczy widoków najwyższego poziomu na stosie, który zawiera
NVARCHARiINTkolumny dla kolumnWKTypeiWKIndex. - Modyfikować garść
UDFs, które odwołują się do tych poglądów typu uniknąć konwersji w niektórych dołączyć predykaty (nasz największy stół audytu jest 500-2,000M wierszy i przechowujeINTwNVARCHAR(4000)kolumnie, który jest używany do przyłączenia przeciwkoWKIndexkolumnie (INT)). - Schemabind the views
- Dodaj kilka indeksów do widoków
- Odbuduj wyzwalacze w widokach za pomocą ustawionej logiki zamiast kursorów
Teraz moje aktualne pytania:
- Czy istnieje metoda najlepszych praktyk do obsługi zlokalizowanych ciągów za pomocą widoku?
- Jakie są alternatywy dla zastosowania kodu pośredniczącego
UDF? (Mogę napisać konkretnyVIEWdla każdego właściciela schematu i na stałe napisać język zamiast polegać na różnych kodach pośredniczącychUDF). - Czy widoki te można po prostu uczynić deterministycznymi, w pełni kwalifikując zagnieżdżone
UDFs, a następnie schematyzując stosy widoków?




UDFdefinicję. Zobacz też Funkcje zdefiniowane przez użytkownika T-SQL: dobre, złe i brzydkie