SQL Server - Xử lý nội địa hóa các chuỗi trong ngăn xếp khung nhìn không xác định lồng nhau


20

Trong khi định hình một cơ sở dữ liệu, tôi đã bắt gặp một khung nhìn đang tham chiếu một số hàm không xác định được truy cập 1000-2500 lần mỗi phút cho mỗi kết nối trong nhóm ứng dụng này. Một đơn giản SELECTtừ khung nhìn mang lại kế hoạch thực hiện sau:

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

Đó dường như là một kế hoạch phức tạp cho một chế độ xem có ít hơn một nghìn hàng có thể thấy một hoặc hai hàng thay đổi cứ sau vài tháng. Nhưng nó trở nên tồi tệ hơn với các quan sát khác sau đây:

  1. Các khung nhìn lồng nhau là không xác định, vì vậy chúng tôi không thể lập chỉ mục cho chúng
  2. Mỗi khung nhìn tham chiếu nhiều UDFs để xây dựng chuỗi
  3. Mỗi UDF chứa các UDFs lồng nhau để lấy mã ISO cho các ngôn ngữ được bản địa hóa
  4. Lượt xem trong ngăn xếp đang sử dụng các trình tạo chuỗi bổ sung được trả về từ UDFs làm JOINvị ngữ
  5. Mỗi ngăn xếp xem được coi là một bảng, có nghĩa là có INSERT/ UPDATE/ DELETEkích hoạt trên mỗi bảng để ghi vào các bảng bên dưới
  6. Những trigger trên quan điểm sử dụng CURSORSrằng EXECthủ tục được lưu trữ mà tham khảo thêm các chuỗi tòa nhà UDFs.

Điều này có vẻ khá thối với tôi, nhưng tôi chỉ có vài năm kinh nghiệm với TSQL. Nó cũng trở nên tốt hơn!

Có vẻ như nhà phát triển đã quyết định rằng đây là một ý tưởng tuyệt vời, đã làm tất cả những điều này để vài trăm chuỗi được lưu trữ có thể có một bản dịch dựa trên một chuỗi được trả về từ một chuỗi UDFcụ thể.

Đây là một trong những khung nhìn trong ngăn xếp, nhưng chúng đều tệ như nhau:

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

Đây là lý do tại sao UDFs đang được sử dụng như JOINvị ngữ. Các I18NIDcột được hình thành bằng cách ghép:STRING + [ + ID + | + ID + ]

Trong quá trình thử nghiệm, một đơn giản SELECTtừ chế độ xem trả về ~ 309 hàng và mất 900-1400ms để thực thi. Nếu tôi kết xuất các chuỗi vào một bảng khác và đặt một chỉ mục trên đó, cùng một lựa chọn sẽ trả về trong 20-75ms.

Vì vậy, câu chuyện dài (và tôi hy vọng bạn đánh giá cao một số điều ngớ ngẩn này) Tôi muốn trở thành một người Samari tốt và thiết kế lại và viết lại điều này cho 99% khách hàng đang chạy sản phẩm này không sử dụng bất kỳ nội địa hóa nào- người dùng -end dự kiến ​​sẽ sử dụng [en-US]ngôn ngữ ngay cả khi tiếng Anh là ngôn ngữ thứ 2/3.

Vì đây là một hack không chính thức, tôi nghĩ về những điều sau đây:

  1. Tạo một bảng Chuỗi mới được điền với một tập hợp dữ liệu được nối sạch từ các bảng cơ sở ban đầu
  2. Lập chỉ mục bảng.
  3. Tạo một tập hợp thay thế các chế độ xem cấp cao nhất trong ngăn xếp bao gồm NVARCHARINTcác cột cho các cột WKTypeWKIndexcột.
  4. Sửa đổi một số ít UDFtham chiếu các chế độ xem này để tránh chuyển đổi loại trong một số vị từ tham gia (bảng kiểm toán lớn nhất của chúng tôi là 500-2.000M hàng và lưu trữ INTmột NVARCHAR(4000)cột được sử dụng để nối với WKIndexcột ( INT).)
  5. Schemabind quan điểm
  6. Thêm một vài chỉ mục để xem
  7. Xây dựng lại các kích hoạt trên các khung nhìn bằng cách sử dụng bộ logic thay vì con trỏ

Bây giờ, câu hỏi thực tế của tôi:

  1. Có một phương pháp thực hành tốt nhất để xử lý các chuỗi cục bộ thông qua một khung nhìn không?
  2. Những lựa chọn thay thế tồn tại để sử dụng UDFnhư một sơ khai? (Tôi có thể viết một cụ thể VIEWcho từng chủ sở hữu lược đồ và mã hóa ngôn ngữ thay vì dựa vào nhiều loại sơ UDFkhai.)
  3. Những khung nhìn này có thể được thực hiện một cách đơn giản bằng cách xác định đầy đủ các UDFs lồng nhau và sau đó lập sơ đồ các ngăn xếp khung nhìn không?

5
Hãy thử chuyển đổi UDF vô hướng thành bảng nội tuyến có giá trị UDF . Gửi UDFđịnh nghĩa của bạn là tốt. Ngoài ra, hãy tham khảo các Hàm do người dùng T-SQL xác định: tốt, xấu và xấu
Kin Shah

Điều này có giúp bạn trong bất kỳ cách nào? stackoverflow.com/questions/316780/
hy

Câu trả lời:


1

Nhìn vào mã đã cho, chúng ta có thể nói,

  • Đầu tiên, đây không phải là một khung nhìn mà nó phải là một thủ tục được lưu trữ, vì nó không chỉ đọc từ bảng mà còn sử dụng UDF.
  • Thứ hai, UDF không nên được gọi thường xuyên cho cùng một cột. Ở đây, nó được gọi một lần trong phần chọn

    ,dbo.User3StringI18N_KeyValue(b.WKType, b.WKIndex, N'WKS') AS I18NID 

    và lần thứ hai tham gia

    .IETFLangCode = dbo.User3StringI18N_KeyValue(b.WKType, b.WKIndex, N'WKS')

Người ta có thể tạo các giá trị trong một bảng tạm thời hoặc sử dụng CTE (Biểu thức bảng chung) để có được các giá trị đó ở vị trí đầu tiên trước khi tham gia diễn ra.

Tôi đã tạo một USP mẫu sẽ cung cấp một số cải tiến:

CREATE PROCEDURE usp_UserWKStringI18N
AS
BEGIN
    -- Do operation using UDF 
    SELECT b.WKType
        ,b.WKIndex
        ,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
    INTO #tempTable
    FROM UserWKStringBASE b;

    -- Now final Select
    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
        ,b.I18NID
        ,b.IETFSessionLangCode
        ,b.IETFDatabaseLangCode
    FROM #tempTable b
    LEFT OUTER JOIN User3StringI18N il
        ON il.I18NID = b.I18NID
            AND il.IETFLangCode = b.IETFSessionLangCode
    LEFT OUTER JOIN User3StringI18N id
        ON id.I18NID = b.I18NID
            AND id.IETFLangCode = b.IETFDatabaseLangCode
END

Hãy thử nó


Xin chào MarmiK, cảm ơn bạn đã dành thời gian để xem bài viết này. Thật không may, đây là một khung nhìn (trong một loạt các khung nhìn lồng nhau) vì vậy việc chuyển nó sang một thủ tục được lưu trữ là không cần thiết.
ong

trong trường hợp đó, chúng ta có thể sử dụng CTE trong chế độ xem vì các bảng tạm thời không được khuyến nghị trong Chế độ xem. HOẶC các hàng của bảng tạm thời có thể được tạo bởi một số thủ tục được lưu trữ và có thể được gọi trong dạng xem.
MarmiK
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.