SQL Server - การจัดการการแปลสตริงในที่ซ้อนกันแบบ non-deterministic


20

ในขณะทำโปรไฟล์ฐานข้อมูลฉันพบว่ามีการอ้างอิงฟังก์ชั่นที่ไม่ได้กำหนดค่าบางอย่างที่เข้าถึง1,000-2500 ครั้งต่อนาทีสำหรับการเชื่อมต่อแต่ละครั้งในแอพพลิเคชั่นนี้ วิSELECTจากมุมมองทำให้แผนการดำเนินการต่อไปนี้:

ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่

ดูเหมือนว่าแผนซับซ้อนสำหรับมุมมองที่มีน้อยกว่าหนึ่งพันแถวที่อาจเห็นการเปลี่ยนแปลงหนึ่งหรือสองแถวทุกสองสามเดือน แต่มันก็แย่ลงด้วยการปฏิบัติอื่น ๆ ดังต่อไปนี้:

  1. มุมมองแบบซ้อนไม่สามารถกำหนดค่าได้ดังนั้นเราจึงไม่สามารถจัดทำดัชนีได้
  2. แต่ละมุมมองอ้างอิงหลายUDFs เพื่อสร้างสตริง
  3. UDF แต่ละอันประกอบด้วยUDFs ที่ซ้อนกันเพื่อรับรหัส ISO สำหรับภาษาที่แปลเป็นภาษาท้องถิ่น
  4. ผู้ชมในกองกำลังใช้เพิ่มเติมสร้างสตริงกลับมาจากUDFการเป็นJOINภาค
  5. มุมมองสแต็กแต่ละครั้งจะถือว่าเป็นตารางหมายความว่ามีINSERT/ UPDATE/ DELETEทริกเกอร์ในแต่ละเพื่อเขียนไปยังตารางพื้นฐาน
  6. ทริกเกอร์เหล่านี้ในมุมมองใช้CURSORSว่าEXECวิธีการจัดเก็บที่อ้างอิงมากกว่านี้สตริงสร้างUDFs

ดูเหมือนว่าฉันจะเน่าเสีย แต่ฉันมีประสบการณ์กับ 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

นี่คือเหตุผลที่UDFs ถูกใช้เป็นเพJOINรดิเคต I18NIDคอลัมน์จะเกิดขึ้นโดยเชื่อมโยง:STRING + [ + ID + | + ID + ]

ในระหว่างการทดสอบเหล่านี้ง่าย ๆSELECTจากมุมมองส่งกลับ ~ 309 แถวและใช้เวลา 900-1400ms เพื่อดำเนินการ ถ้าฉันดัมพ์สตริงลงในตารางอื่นและตบดัชนีบนมันการเลือกเดียวกันจะส่งคืนภายใน 20-75ms

เรื่องสั้นสั้น ๆ (และฉันหวังว่าคุณจะพอใจกับความโง่เขลานี้) ฉันอยากเป็นชาวสะมาเรียที่ดีและออกแบบใหม่และเขียนสิ่งนี้ใหม่สำหรับลูกค้า 99% ที่ใช้ผลิตภัณฑ์นี้ซึ่งไม่ได้ใช้การแปลภาษาเลย - ผู้ใช้ระดับปลายคาดว่าจะใช้[en-US]ภาษาแม้ในภาษาอังกฤษเป็นภาษาที่ 2/3

เนื่องจากนี่เป็นการแฮ็คอย่างไม่เป็นทางการฉันจึงคิดถึงสิ่งต่อไปนี้:

  1. สร้างตาราง String ใหม่ที่มีชุดข้อมูลที่เข้าร่วมอย่างเรียบร้อยจากตารางฐานดั้งเดิม
  2. จัดทำดัชนีตาราง
  3. สร้างชุดการแทนที่ของมุมมองระดับบนสุดในสแต็กที่รวมNVARCHARและINTคอลัมน์สำหรับWKTypeและWKIndexคอลัมน์
  4. ปรับเปลี่ยนจำนวนUDFเล็กน้อยที่อ้างอิงมุมมองเหล่านี้เพื่อหลีกเลี่ยงการแปลงประเภทในภาคแสดงร่วม (ตารางตรวจสอบที่ใหญ่ที่สุดของเราคือ 500-2,000 ล้านแถวและเก็บINTไว้ในNVARCHAR(4000)คอลัมน์ที่ใช้เพื่อเข้าร่วมกับWKIndexคอลัมน์ ( INT))
  5. วางแผนมุมมอง
  6. เพิ่มดัชนีบางอย่างในมุมมอง
  7. สร้างทริกเกอร์ในมุมมองอีกครั้งโดยใช้ set ตรรกะแทนเคอร์เซอร์

ตอนนี้คำถามจริงของฉัน:

  1. มีวิธีปฏิบัติที่ดีที่สุดในการจัดการสตริงที่แปลผ่านมุมมองหรือไม่?
  2. มีทางเลือกใดUDFบ้างสำหรับใช้เป็นสตับ (ฉันสามารถเขียนข้อมูลเฉพาะVIEWสำหรับเจ้าของสคีมาแต่ละภาษาและเขียนโค้ดภาษายาก ๆ แทนที่จะพึ่งพาสUDFตับที่หลากหลาย)
  3. มุมมองเหล่านี้สามารถกำหนดได้ง่าย ๆ โดยการคัดเลือกUDFs ที่ซ้อนกันทั้งหมดแล้วจึงวางแผนดูสแต็ก?

5
พยายามที่จะแปลงเกลา UDF ไปยังตาราง Inline มูลค่า UDF โพสต์UDFคำจำกัดความของคุณเช่นกัน นอกจากนี้อ้างถึงฟังก์ชั่นที่ผู้ใช้กำหนดเองของ T-SQL: ข้อดีข้อเสียและน่าเกลียด
Kin Shah

สิ่งนี้ช่วยคุณได้บ้างไหม? stackoverflow.com/questions/316780/…
stacylaray

หรืออันนี้ stackoverflow.com/questions/258483/…
stacylaray

คำตอบ:


1

ดูรหัสที่กำหนดเราสามารถพูดได้

  • อันดับแรกสิ่งนี้ไม่ควรเป็นมุมมอง แต่ควรเป็นขั้นตอนการจัดเก็บเนื่องจากไม่ใช่แค่อ่านจากตาราง แต่ใช้ UDF
  • ประการที่สองไม่ควรเรียกใช้ UDF บ่อยครั้งสำหรับคอลัมน์เดียวกัน ที่นี่มันถูกเรียกว่าครั้งเดียวในการเลือก

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

    และครั้งที่สองสำหรับการเข้าร่วม

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

หนึ่งสามารถสร้างค่าในตารางชั่วคราวหรือใช้ CTE (Common Table Expression) เพื่อรับค่าเหล่านั้นในสถานที่แรกก่อนที่จะเข้าร่วมเกิดขึ้น

ฉันได้สร้างตัวอย่าง USP ที่จะให้การปรับปรุงบางอย่าง:

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

โปรดลองสิ่งนี้


สวัสดี MarmiK ขอบคุณที่สละเวลาอ่านโพสต์นี้ นี่เป็นมุมมองที่น่าเสียดาย (ในมุมมองแบบซ้อน) ดังนั้นการย้ายไปยังขั้นตอนการจัดเก็บนั้นหมดไปจากคำถาม
beeks

ในกรณีนี้เราสามารถใช้ CTE ในมุมมองได้เนื่องจากไม่แนะนำให้ใช้ temp tables ใน View หรือแถวของตาราง temp สามารถสร้างขึ้นได้โดยบางโพรซีเดอร์ที่เก็บไว้และสามารถเรียกใช้ในมุมมอง
MarmiK
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.