แผนการดำเนินการแสดงการดำเนินการ CONVERT_IMPLICIT ราคาแพง ฉันสามารถแก้ไขสิ่งนี้ด้วยการจัดทำดัชนีหรือฉันจำเป็นต้องเปลี่ยนตารางหรือไม่?


24

ฉันมีมุมมองที่สำคัญและช้ามาก ๆ ซึ่งรวมถึงเงื่อนไขที่น่าเกลียดบางอย่างเช่นนี้ในส่วนที่ ฉันยังทราบด้วยว่าการรวมนั้นเป็นการรวมแบบรวมและแบบช้าในvarchar(13)แทนที่จะเป็นฟิลด์จำนวนเต็ม แต่ต้องการปรับปรุงการค้นหาแบบง่ายด้านล่างที่ใช้มุมมองนี้:

CREATE VIEW [dbo].[vwReallySlowView]  AS  
AS  
SELECT     
  I.booking_no_v32 AS bkno, 
  I.trans_type_v41 AS trantype, 
  B.Assigned_to_v61 AS Assignbk, 
  B.order_date AS dateo, B.HourBooked AS HBooked,   
  B.MinBooked AS MBooked, B.SecBooked AS SBooked, 
  I.prep_on AS Pon, I.From_locn AS Flocn, 
  I.Trans_to_locn AS TTlocn,   
                      (CASE I.prep_on WHEN 'Y' THEN I.PDate ELSE I.FirstDate END) AS PrDate, I.PTimeH AS PrTimeH, I.PTimeM AS PrTimeM,   
                      (CASE WHEN I.RetnDate < I.FirstDate THEN I.FirstDate ELSE I.RetnDate END) AS RDatev, I.bit_field_v41 AS bitField, I.FirstDate AS FDatev, I.BookDate AS DBooked,   
                      I.TimeBookedH AS TBookH, I.TimeBookedM AS TBookM, I.TimeBookedS AS TBookS, I.del_time_hour AS dth, I.del_time_min AS dtm, I.return_to_locn AS rtlocn,   
                      I.return_time_hour AS rth, I.return_time_min AS rtm, (CASE WHEN I.Trans_type_v41 IN (6, 7) AND (I.Trans_qty < I.QtyCheckedOut)   
                      THEN 0 WHEN I.Trans_type_v41 IN (6, 7) AND (I.Trans_qty >= I.QtyCheckedOut) THEN I.Trans_Qty - I.QtyCheckedOut ELSE I.trans_qty END) AS trqty,   
                      (CASE WHEN I.Trans_type_v41 IN (6, 7) THEN 0 ELSE I.QtyCheckedOut END) AS MyQtycheckedout, (CASE WHEN I.Trans_type_v41 IN (6, 7)   
                      THEN 0 ELSE I.QtyReturned END) AS retqty, I.ID, B.BookingProgressStatus AS bkProg, I.product_code_v42, I.return_to_locn, I.AssignTo, I.AssignType,   
                      I.QtyReserved, B.DeprepOn,  
        (CASE  B.DeprepOn       
        WHEN 1 THEN  B.DeprepDateTime     
        ELSE   I.RetnDate  
           END)  AS DeprepDateTime, I.InRack 
FROM         dbo.tblItemtran AS I 

INNER JOIN  -- booking_no = varchar(13)
         dbo.tblbookings AS B ON B.booking_no = I.booking_no_v32  --  string inner-join

INNER JOIN  -- product_code = varchar(13) 
        dbo.tblInvmas AS M ON I.product_code_v42 = M.product_code  --  string inner-join

WHERE     (I.trans_type_v41 NOT IN (2, 3, 7, 18, 19, 20, 21, 12, 13, 22)) AND (I.trans_type_v41 NOT IN (6, 7)) AND (I.bit_field_v41 & 4 = 0) OR  
                      (I.trans_type_v41 NOT IN (6, 7)) AND (I.bit_field_v41 & 4 = 0) AND (B.BookingProgressStatus = 1) OR  
                      (I.trans_type_v41 IN (6, 7)) AND (I.bit_field_v41 & 4 = 0) AND (I.QtyCheckedOut = 0) OR  
                      (I.trans_type_v41 IN (6, 7)) AND (I.bit_field_v41 & 4 = 0) AND (I.QtyCheckedOut > 0) AND (I.trans_qty - (I.QtyCheckedOut - I.QtyReturned) > 0)  

มุมมองนี้มักใช้แบบนี้:

select * from vwReallySlowView
where product_code_v42  = 'LIGHTBULB100W'  -- find "100 watt lightbulb" rows

เมื่อฉันเรียกฉันได้รับนี้รายการแผนปฏิบัติการต้นทุน 20-80% ของต้นทุนรวมของชุดที่มีกริยาCONVERT_IMPLICIT( .... &(4))แสดงให้เห็นว่ามันน่าจะเป็นช้ามากที่ทำเหล่านี้เช่น bitwise boolean tests(I.ibitfield & 4 = 0)

ฉันไม่ใช่ผู้เชี่ยวชาญใน MS SQL หรือที่งาน DBA โดยทั่วไปเนื่องจากฉันเป็นนักพัฒนาซอฟต์แวร์ที่ไม่ใช่ SQL ส่วนใหญ่ แต่ฉันสงสัยว่าชุดค่าผสมแบบบิตนั้นเป็นความคิดที่ไม่ดีและมันจะดีกว่าถ้ามีเขตบูลีนแบบแยก

ฉันสามารถปรับปรุงดัชนีนี้ได้หรือไม่เพื่อจัดการกับมุมมองนี้โดยไม่ต้องเปลี่ยน schema (ซึ่งมีอยู่แล้วในการผลิตที่หลายพันแห่ง) แล้วหรือฉันต้องเปลี่ยนตารางพื้นฐานที่มีค่าบูลีนหลายค่าที่บรรจุเป็นจำนวนเต็มbit_field_v41เพื่อแก้ไขปัญหานี้ ?

นี่คือดัชนีกลุ่มของฉันtblItemtranซึ่งกำลังถูกสแกนในแผนการดำเนินการนี้:

-- goal:  speed up  select * from vwReallySlowView where productcode  = 'X'
CREATE CLUSTERED INDEX [idxtblItemTranProductCodeAndTransType] ON [dbo].[tblItemtran] 
(
    [product_code_v42] ASC,  -- varchar(13)
    [trans_type_v41] ASC     -- int
)WITH ( PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, 
        IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, 
        ALLOW_PAGE_LOCKS  = ON) 
ON [PRIMARY]

นี่คือแผนปฏิบัติการสำหรับหนึ่งในผลิตภัณฑ์อื่น ๆ ที่ส่งผลให้ค่าใช้จ่าย 27% เกี่ยวกับเรื่องนี้CONVERT_IMPLICITกริยา อัปเดตโปรดทราบว่าในกรณีนี้โหนดที่แย่ที่สุดของฉันคือ "แฮชที่ตรงกัน" inner joinซึ่งมีราคา 34% ฉันเชื่อว่านี่คือค่าใช้จ่ายที่ฉันไม่สามารถหลีกเลี่ยงได้ กำจัด. ทั้งการINNER JOINดำเนินการในมุมมองด้านบนอยู่ในvarchar(13)ฟิลด์

ซูมเข้าที่มุมล่างขวา:

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

แผนการดำเนินการทั้งหมดเป็น. sqlplan พร้อมใช้งานบน skydrive ภาพนี้เป็นเพียงภาพรวมของภาพ คลิกที่นี่เพื่อดูภาพด้วยตัวเอง

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

อัพเดทแผนการดำเนินการทั้งหมดที่โพสต์ ฉันไม่สามารถหาสิ่งที่product_codeคุ้มค่าทางพยาธิวิทยา แต่วิธีหนึ่งในการทำเช่นนั้นคือselect count(*) from viewแทนที่จะทำผลิตภัณฑ์เดียว แต่ผลิตภัณฑ์ที่ใช้ใน 5% ของระเบียนในตารางอ้างอิงหรือน้อยกว่าดูเหมือนจะแสดงต้นทุนที่ต่ำกว่าในการCONVERT_IMPLICIT ดำเนินการ ถ้าฉันจะแก้ไข SQL ที่นี่ฉันคิดว่าฉันใช้WHEREประโยคขั้นต้นในมุมมองและคำนวณและจัดเก็บผลลัพธ์ของยักษ์ที่ซึ่งอนุประโยคเงื่อนไขเป็นบิต "IncludeMeInTheView" bit-field ในตารางต้นแบบ . โอมเพี้ยงแก้ปัญหาใช่มั้ย



. SQLPLAN ที่ฉันโพสต์นั้นมีพยาธิสภาพน้อยกว่าเคส 432k / 17k ในภาพต้นฉบับ ฉันขอโทษที่ฉันไม่สามารถหาproduct_codeค่าที่ฉันใช้ในการสร้าง87%กรณีทางพยาธิวิทยาด้วยข้อมูลของฉันได้อีก 27%ภาพในขณะนี้แสดงให้เห็น อีกครั้งขอโทษสำหรับความสับสนเนื่องจากการแก้ไขของฉัน
Warren P

คำตอบ:


49

คุณไม่ควรพึ่งพาเปอร์เซ็นต์ค่าใช้จ่ายมากเกินไปในแผนการดำเนินการ ค่าใช้จ่ายเหล่านี้เป็นค่าใช้จ่ายโดยประมาณเสมอแม้ในแผนการดำเนินการภายหลังที่มีหมายเลข 'จริง' สำหรับสิ่งต่าง ๆ เช่นการนับแถว ค่าใช้จ่ายโดยประมาณนั้นขึ้นอยู่กับแบบจำลองที่ทำงานได้ค่อนข้างดีสำหรับจุดประสงค์: เปิดใช้งานเครื่องมือเพิ่มประสิทธิภาพให้เลือกระหว่างแผนการดำเนินการของผู้สมัครที่แตกต่างกันสำหรับแบบสอบถามเดียวกัน ข้อมูลค่าใช้จ่ายน่าสนใจและเป็นปัจจัยที่ควรพิจารณา แต่ไม่ค่อยน่าจะเป็นตัวชี้วัดหลักสำหรับการปรับแต่งแบบสอบถาม การตีความข้อมูลแผนปฏิบัติการจำเป็นต้องมีมุมมองที่กว้างขึ้นของข้อมูลที่นำเสนอ

ItemTran กลุ่มดัชนีแสวงหาผู้ประกอบการ

ค้นหาดัชนีของกลุ่ม ItemTran

ตัวดำเนินการนี้มีสองการดำเนินการในหนึ่งเดียว ครั้งแรกที่ดัชนีแสวงหาการดำเนินงานพบว่าทุกแถวที่ตรงกับคำกริยาproduct_code_v42 = 'M10BOLT'แล้วแต่ละแถวมีกริยาที่เหลือbit_field_v41 & 4 = 0นำไปใช้ มีการแปลงนัยคือbit_field_v41จากชนิดฐาน ( tinyintหรือsmallint) integerเพื่อ

การแปลงเกิดขึ้นเนื่องจากตัวดำเนินการbitwise-AND (&) ต้องการให้ตัวถูกดำเนินการทั้งสองเป็นประเภทเดียวกัน ประเภทโดยนัยของค่าคงที่ '4' เป็นจำนวนเต็มและกฎสำคัญกว่าประเภทข้อมูลหมายถึงbit_field_v41ค่าฟิลด์ที่มีลำดับความสำคัญต่ำกว่าจะถูกแปลง

ปัญหา (เช่นนั้น) สามารถแก้ไขได้อย่างง่ายดายโดยการเขียนภาคแสดงbit_field_v41 & CONVERT(tinyint, 4) = 0- หมายถึงค่าคงที่มีลำดับความสำคัญต่ำกว่าและถูกแปลง (ระหว่างการพับคงที่) แทนที่จะเป็นค่าคอลัมน์ ถ้าbit_field_v41เป็นtinyintไม่มี Conversion เกิดขึ้นทั้งหมด ในทำนองเดียวกันCONVERT(smallint, 4)สามารถนำมาใช้ในกรณีที่เป็นbit_field_v41 smallintดังกล่าวกล่าวว่าการแปลงไม่ใช่ปัญหาด้านประสิทธิภาพในกรณีนี้ แต่ก็ยังมีแนวปฏิบัติที่ดีในการจับคู่ประเภทและหลีกเลี่ยงการแปลงโดยนัยหากเป็นไปได้

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

เมื่อมองไปที่คอลัมน์การค้นหาส่วนที่เหลือและคอลัมน์ผลลัพธ์ประสิทธิภาพของตัวดำเนินการนี้สามารถตรวจสอบได้โดยการสร้างแบบสอบถามที่เทียบเท่า ( 1 <> 2เป็นกลอุบายเพื่อป้องกันการกำหนดพารามิเตอร์อัตโนมัติความขัดแย้งจะถูกลบโดยเครื่องมือเพิ่มประสิทธิภาพและไม่ปรากฏใน แผนแบบสอบถาม):

SELECT
    it.booking_no_v32,
    it.QtyCheckedOut,
    it.QtyReturned,
    it.Trans_qty,
    it.trans_type_v41
FROM dbo.tblItemTran AS it
WHERE
    1 <> 2
    AND it.product_code_v42 = 'M10BOLT'
    AND it.bit_field_v41 & CONVERT(tinyint, 4) = 0;

ประสิทธิภาพของแบบสอบถามนี้ด้วยแคชข้อมูลเย็นเป็นที่สนใจเนื่องจากการอ่านล่วงหน้าจะได้รับผลกระทบจากการแตกแฟรกเมนต์ตาราง (ดัชนีคลัสเตอร์) คีย์การทำคลัสเตอร์สำหรับตารางนี้เชิญการแตกแฟรกเมนต์ดังนั้นจึงเป็นสิ่งสำคัญในการบำรุงรักษา (จัดระเบียบใหม่หรือสร้างใหม่) ดัชนีนี้เป็นประจำและใช้ที่เหมาะสมFILLFACTORเพื่อให้มีพื้นที่ว่างสำหรับแถวใหม่ระหว่างหน้าต่างการบำรุงรักษาดัชนี

ผมดำเนินการทดสอบผลกระทบของการกระจายตัวบนอ่านล่วงหน้าโดยใช้ข้อมูลตัวอย่างสร้างขึ้นโดยใช้ข้อมูล Generator การใช้แถวตารางเดียวกันจะนับตามที่แสดงในแผนคิวรีของคำถามดัชนีที่กระจัดกระจายอย่างมากทำให้SELECT * FROM viewใช้เวลา 15 วินาทีหลังจากDBCC DROPCLEANBUFFERSนั้น การทดสอบเดียวกันในเงื่อนไขเดียวกันกับดัชนีคลัสเตอร์ที่สร้างใหม่สดใหม่บนตาราง ItemTrans เสร็จสมบูรณ์ภายใน 3 วินาที

หากข้อมูลตารางโดยทั่วไปอยู่ในแคชปัญหาการกระจายตัวของข้อมูลมีความสำคัญน้อยกว่ามาก แต่แม้จะมีการกระจายตัวต่ำแถวแถวกว้างอาจหมายถึงจำนวนการอ่านเชิงตรรกะและทางกายภาพสูงกว่าที่คาดไว้มาก นอกจากนี้คุณยังสามารถทดสอบด้วยการเพิ่มและลบคำCONVERTชี้แจงออกมาเพื่อตรวจสอบความคาดหวังของฉันว่าปัญหาการแปลงโดยนัยไม่สำคัญที่นี่ยกเว้นเป็นการละเมิดวิธีปฏิบัติที่ดีที่สุด

ยิ่งไปกว่านั้นคือจำนวนแถวโดยประมาณที่ออกจากตัวดำเนินการค้นหา การประเมินเวลาการปรับให้เหมาะสมคือ 165 แถว แต่มีการผลิต 4,226 ครั้งในขณะดำเนินการ ฉันจะกลับมาที่จุดนี้ในภายหลัง แต่เหตุผลหลักสำหรับความคลาดเคลื่อนคือการเลือกของส่วนที่เหลือ (ที่เกี่ยวข้องกับ bitwise-AND) นั้นยากมากสำหรับเครื่องมือเพิ่มประสิทธิภาพในการทำนาย

ผู้ประกอบการตัวกรอง

ผู้ประกอบการตัวกรอง

ฉันกำลังแสดงคำกริยาตัวกรองที่นี่ส่วนใหญ่เพื่อแสดงให้เห็นว่าทั้งสองNOT INรายการจะรวมกันง่ายขึ้นและขยายแล้วและยังให้การอ้างอิงสำหรับการอภิปรายการจับคู่แฮชต่อไปนี้ แบบสอบถามทดสอบจากการค้นหาสามารถขยายเพื่อรวมผลกระทบและกำหนดผลกระทบของตัวดำเนินการตัวกรองต่อประสิทธิภาพ:

SELECT
    it.booking_no_v32,
    it.trans_type_v41,
    it.Trans_qty,
    it.QtyReturned,
    it.QtyCheckedOut
FROM dbo.tblItemTran AS it
WHERE
    it.product_code_v42 = 'M10BOLT'
    AND it.bit_field_v41 & CONVERT(tinyint, 4) = 0
    AND
    (
        (
            it.trans_type_v41 NOT IN (2, 3, 6, 7, 18, 19, 20, 21, 12, 13, 22)
            AND it.trans_type_v41 NOT IN (6, 7)
        )
        OR
        (
            it.trans_type_v41 NOT IN (6, 7)
        )
        OR 
        (
            it.trans_type_v41 IN (6, 7)
            AND it.QtyCheckedOut = 0
        )
        OR 
        (
            it.trans_type_v41 IN (6, 7)
            AND it.QtyCheckedOut > 0
            AND it.trans_qty - (it.QtyCheckedOut - it.QtyReturned) > 0
        )
    );

ตัวดำเนินการคำนวณสเกลาร์ในแผนกำหนดนิพจน์ต่อไปนี้ (การคำนวณตัวเองถูกเลื่อนออกไปจนกว่าผลลัพธ์จะถูกดำเนินการโดยผู้ดำเนินการภายหลัง)

[Expr1016] = (trans_qty - (QtyCheckedOut - QtyReturned))

ตัวดำเนินการ Hash Match

การเข้าร่วมกับประเภทข้อมูลอักขระไม่ใช่เหตุผลของค่าใช้จ่ายโดยประมาณที่สูงของผู้ให้บริการนี้ คำแนะนำเครื่องมือ SSMS แสดงเฉพาะรายการโพรบ Hash Keys เท่านั้น แต่รายละเอียดที่สำคัญอยู่ในหน้าต่างคุณสมบัติ SSMS

ตัวดำเนินการ Hash Match จะสร้างตารางแฮชโดยใช้ค่าของbooking_no_v32คอลัมน์ (Hash Keys Build) จากตาราง ItemTran จากนั้นตรวจสอบการจับคู่โดยใช้booking_noคอลัมน์ (Hash Keys Probe) จากตาราง Bookings คำแนะนำเครื่องมือ SSMS จะแสดง Probe Residual ด้วย แต่ข้อความนั้นยาวเกินไปสำหรับคำแนะนำเครื่องมือและถูกตัดออกไป

Probe Residual คล้ายกับ Residual ที่เห็นหลังจากดัชนีค้นหาก่อนหน้านี้ เพรดิเคตที่เหลือจะถูกประเมินในทุกแถวที่แฮชตรงกันเพื่อกำหนดว่าควรส่งผ่านแถวไปยังโอเปอเรเตอร์หลักหรือไม่ การค้นหาการจับคู่แฮชในตารางแฮชที่มีความสมดุลนั้นเร็วมาก แต่การใช้เพรดิเคตที่ซับซ้อนกับแต่ละแถวที่ตรงกันค่อนข้างช้าโดยการเปรียบเทียบ เคล็ดลับเครื่องมือ Hash Match ใน Plan Explorer แสดงรายละเอียดรวมถึงนิพจน์ที่เหลือของ Probe:

ตัวดำเนินการจับคู่แบบแฮช

เพรดิเคตที่เหลือมีความซับซ้อนและรวมถึงการตรวจสอบสถานะความคืบหน้าการจองตอนนี้คอลัมน์นั้นพร้อมใช้งานจากตารางจอง เคล็ดลับเครื่องมือยังแสดงความคลาดเคลื่อนที่เหมือนกันระหว่างจำนวนแถวโดยประมาณกับจำนวนแถวจริงที่เห็นก่อนหน้านี้ในการค้นหาดัชนี อาจดูเหมือนว่าการกรองส่วนใหญ่ดำเนินการสองครั้ง แต่นี่เป็นเพียงเครื่องมือเพิ่มประสิทธิภาพเท่านั้นที่มองในแง่ดี ไม่คาดหวังว่าชิ้นส่วนของตัวกรองที่สามารถผลักลงแผนจากหัวตรวจวัดที่เหลือเพื่อกำจัดแถวใด ๆ (การประมาณจำนวนแถวเหมือนกันทั้งก่อนและหลังตัวกรอง) แต่เครื่องมือเพิ่มประสิทธิภาพรู้ว่ามันอาจผิด โอกาสในการกรองแถวก่อน (ลดค่าใช้จ่ายของการเข้าร่วมแฮช) จะคุ้มค่ากับค่าใช้จ่ายเล็กน้อยของตัวกรองพิเศษ ไม่สามารถผลักตัวกรองทั้งหมดลงเนื่องจากมีการทดสอบคอลัมน์จากตารางการจอง แต่ส่วนใหญ่สามารถทำได้

การนับแถวดูถูกดูแคลนเป็นปัญหาสำหรับตัวดำเนินการจับคู่แฮชเนื่องจากจำนวนหน่วยความจำที่สงวนไว้สำหรับตารางแฮชจะขึ้นอยู่กับจำนวนแถวโดยประมาณ ในกรณีที่หน่วยความจำที่มีขนาดเล็กเกินไปสำหรับขนาดของตารางแฮชที่จำเป็นต้องใช้ในเวลาทำงาน (เนื่องจากจำนวนขนาดใหญ่ของแถว) ตารางแฮชซ้ำรั่วไหลทางกายภาพtempdbจัดเก็บข้อมูลมักจะเกิดในประสิทธิภาพที่ดีมาก ในกรณีที่แย่ที่สุดเอ็นจิ้นการประมวลผลจะหยุดการทำแฮ็คถังและรีสอร์ตซ้ำ ๆ เพื่อให้ช้ามากอัลกอริทึม bailout Hash spilling (เรียกซ้ำหรือ bailout) เป็นสาเหตุที่เป็นไปได้มากที่สุดของปัญหาประสิทธิภาพที่ระบุไว้ในคำถาม (ไม่ใช่คอลัมน์เข้าร่วมประเภทตัวอักษรหรือการแปลงโดยนัย) สาเหตุหลักน่าจะเกิดจากเซิร์ฟเวอร์ที่จองหน่วยความจำน้อยเกินไปสำหรับการสืบค้นโดยพิจารณาจากจำนวนแถวที่ไม่ถูกต้อง (cardinality)

น่าเศร้าที่ก่อน SQL Server 2012 ไม่มีข้อบ่งชี้ในแผนการดำเนินการว่าการดำเนินการ hashing เกินกว่าการจัดสรรหน่วยความจำ (ซึ่งไม่สามารถเติบโตแบบไดนามิกหลังจากถูกสงวนไว้ก่อนการดำเนินการเริ่มต้นแม้ว่าเซิร์ฟเวอร์จะมีหน่วยความจำว่างจำนวนมาก) tempdb เป็นไปได้ที่จะตรวจสอบHash Warning Event Classโดยใช้ Profiler แต่มันอาจเป็นเรื่องยากที่จะเชื่อมโยงคำเตือนกับแบบสอบถามเฉพาะ

การแก้ไขปัญหา

ปัญหาสามประการคือการแตกแฟรกเมนต์โพรบที่ซับซ้อนยังคงอยู่ในตัวดำเนินการจับคู่แฮชและการประมาณค่า cardinality ที่ไม่ถูกต้องซึ่งเป็นผลมาจากการคาดเดาที่การค้นหาดัชนี

วิธีแก้ปัญหาที่แนะนำ

ตรวจสอบการแตกแฟรกเมนต์และแก้ไขหากจำเป็นกำหนดเวลาการบำรุงรักษาเพื่อให้แน่ใจว่าดัชนียังคงเป็นที่ยอมรับ วิธีปกติในการแก้ไขค่าประมาณของ cardinality คือการจัดทำสถิติ ในกรณีนี้เครื่องมือเพิ่มประสิทธิภาพต้องมีสถิติสำหรับชุดค่าผสม ( product_code_v42, bitfield_v41 & 4 = 0) เราไม่สามารถสร้างสถิติในนิพจน์โดยตรงดังนั้นเราต้องสร้างคอลัมน์จากการคำนวณสำหรับนิพจน์ฟิลด์บิตจากนั้นสร้างสถิติหลายคอลัมน์แบบแมนนวล:

ALTER TABLE dbo.tblItemTran
ADD Bit3 AS bit_field_v41 & CONVERT(tinyint, 4);

CREATE STATISTICS [stats dbo.ItemTran (product_code_v42, Bit3)]
ON dbo.tblItemTran (product_code_v42, Bit3);

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

สถิติหลายคอลัมน์ควรส่งผลให้การประเมินดีขึ้นมากลดโอกาสที่ผู้ดำเนินการแข่งขันแฮชจะใช้การหกซ้ำหรืออัลกอริทึม bailout การเพิ่มคอลัมน์ที่คำนวณ (ซึ่งเป็นการดำเนินการเมตาดาต้าเท่านั้นและไม่มีพื้นที่ในตารางเนื่องจากไม่ได้ทำเครื่องหมายPERSISTED) และสถิติหลายคอลัมน์คือการคาดเดาที่ดีที่สุดสำหรับโซลูชันแรก

เมื่อแก้ไขปัญหาประสิทธิภาพการสืบค้นสิ่งสำคัญคือการวัดสิ่งต่าง ๆ เช่นเวลาที่ผ่านไปการใช้งาน CPU การอ่านแบบลอจิคัลการอ่านแบบฟิสิคัลชนิดการรอและระยะเวลา ... และอื่น ๆ นอกจากนี้ยังมีประโยชน์ในการเรียกใช้บางส่วนของแบบสอบถามแยกต่างหากเพื่อตรวจสอบสาเหตุที่น่าสงสัยดังที่แสดงด้านบน

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

ดูการจัดทำดัชนี

อย่าล่อลวงให้ทำดัชนีมุมมองดั้งเดิมโดยตรง ประสิทธิภาพการอ่านจะเร็วอย่างน่าอัศจรรย์ (การค้นหาเพียงครั้งเดียวในดัชนีมุมมอง) แต่ (ในกรณีนี้) ปัญหาประสิทธิภาพทั้งหมดในแผนแบบสอบถามที่มีอยู่จะถูกถ่ายโอนไปยังแบบสอบถามที่ปรับเปลี่ยนคอลัมน์ตารางใด ๆ ที่อ้างอิงในมุมมอง คำค้นหาที่เปลี่ยนแถวตารางพื้นฐานจะได้รับผลกระทบไม่ดีอย่างแน่นอน

โซลูชันขั้นสูงพร้อมมุมมองที่จัดทำดัชนีไว้บางส่วน

มีวิธีแก้ปัญหาการดูดัชนีบางส่วนสำหรับการสืบค้นนี้โดยเฉพาะที่แก้ไขการประมาณเชิงลบและลบตัวกรองและโพรบส่วนที่เหลือ แต่ขึ้นอยู่กับสมมติฐานบางอย่างเกี่ยวกับข้อมูล ดัชนีเพื่อสนับสนุนแผนการบำรุงรักษามุมมองที่จัดทำดัชนี ฉันแบ่งปันรหัสด้านล่างเพื่อความสนใจฉันไม่เสนอให้คุณนำไปใช้โดยไม่มีการวิเคราะห์และทดสอบอย่างระมัดระวัง

-- Indexed view to optimize the main view
CREATE VIEW dbo.V1
WITH SCHEMABINDING
AS
SELECT
    it.ID,
    it.product_code_v42,
    it.trans_type_v41,
    it.booking_no_v32,
    it.Trans_qty,
    it.QtyReturned,
    it.QtyCheckedOut,
    it.QtyReserved,
    it.bit_field_v41,
    it.prep_on,
    it.From_locn,
    it.Trans_to_locn,
    it.PDate,
    it.FirstDate,
    it.PTimeH,
    it.PTimeM,
    it.RetnDate,
    it.BookDate,
    it.TimeBookedH,
    it.TimeBookedM,
    it.TimeBookedS,
    it.del_time_hour,
    it.del_time_min,
    it.return_to_locn,
    it.return_time_hour,
    it.return_time_min,
    it.AssignTo,
    it.AssignType,
    it.InRack
FROM dbo.tblItemTran AS it
JOIN dbo.tblBookings AS tb ON
    tb.booking_no = it.booking_no_v32
WHERE
    (
        it.trans_type_v41 NOT IN (2, 3, 7, 18, 19, 20, 21, 12, 13, 22)
        AND it.trans_type_v41 NOT IN (6, 7)
        AND it.bit_field_v41 & CONVERT(tinyint, 4) = 0
    )
    OR
    (
        it.trans_type_v41 NOT IN (6, 7)
        AND it.bit_field_v41 & CONVERT(tinyint, 4) = 0
        AND tb.BookingProgressStatus = 1
    )
    OR 
    (
        it.trans_type_v41 IN (6, 7)
        AND it.bit_field_v41 & CONVERT(tinyint, 4) = 0
        AND it.QtyCheckedOut = 0
    )
    OR 
    (
        it.trans_type_v41 IN (6, 7)
        AND it.bit_field_v41 & CONVERT(tinyint, 4) = 0
        AND it.QtyCheckedOut > 0
        AND it.trans_qty - (it.QtyCheckedOut - it.QtyReturned) > 0
    );
GO
CREATE UNIQUE CLUSTERED INDEX cuq ON dbo.V1 (product_code_v42, ID);
GO

มุมมองที่มีอยู่ tweaked เพื่อใช้มุมมองที่จัดทำดัชนีด้านบน:

CREATE VIEW [dbo].[vwReallySlowView2]
AS
SELECT
    I.booking_no_v32 AS bkno,
    I.trans_type_v41 AS trantype,
    B.Assigned_to_v61 AS Assignbk,
    B.order_date AS dateo,
    B.HourBooked AS HBooked,
    B.MinBooked AS MBooked,
    B.SecBooked AS SBooked,
    I.prep_on AS Pon,
    I.From_locn AS Flocn,
    I.Trans_to_locn AS TTlocn,
    CASE I.prep_on 
        WHEN 'Y' THEN I.PDate
        ELSE I.FirstDate
    END AS PrDate,
    I.PTimeH AS PrTimeH,
    I.PTimeM AS PrTimeM,
    CASE
        WHEN I.RetnDate < I.FirstDate 
        THEN I.FirstDate 
        ELSE I.RetnDate
    END AS RDatev,
    I.bit_field_v41 AS bitField,
    I.FirstDate AS FDatev,
    I.BookDate AS DBooked,
    I.TimeBookedH AS TBookH,
    I.TimeBookedM AS TBookM,
    I.TimeBookedS AS TBookS,
    I.del_time_hour AS dth,
    I.del_time_min AS dtm,
    I.return_to_locn AS rtlocn,
    I.return_time_hour AS rth,
    I.return_time_min AS rtm,
    CASE
        WHEN
            I.Trans_type_v41 IN (6, 7) 
            AND I.Trans_qty < I.QtyCheckedOut
            THEN 0 
        WHEN
            I.Trans_type_v41 IN (6, 7)
            AND I.Trans_qty >= I.QtyCheckedOut
            THEN I.Trans_Qty - I.QtyCheckedOut
        ELSE
            I.trans_qty
    END AS trqty,
    CASE
        WHEN I.Trans_type_v41 IN (6, 7)
        THEN 0
        ELSE I.QtyCheckedOut
    END AS MyQtycheckedout,
    CASE
        WHEN I.Trans_type_v41 IN (6, 7)
        THEN 0
        ELSE I.QtyReturned
    END AS retqty,
    I.ID,
    B.BookingProgressStatus AS bkProg,
    I.product_code_v42,
    I.return_to_locn,
    I.AssignTo,
    I.AssignType,
    I.QtyReserved,
    B.DeprepOn,
    CASE B.DeprepOn
        WHEN 1 THEN B.DeprepDateTime
        ELSE I.RetnDate
    END AS DeprepDateTime,
    I.InRack
FROM dbo.V1 AS I WITH (NOEXPAND)
JOIN dbo.tblbookings AS B ON
    B.booking_no = I.booking_no_v32
JOIN dbo.tblInvmas AS M ON
    I.product_code_v42 = M.product_code;

ตัวอย่างแบบสอบถามและแผนการดำเนินการ:

SELECT
    vrsv.*
FROM dbo.vwReallySlowView2 AS vrsv
WHERE vrsv.product_code_v42 = 'M10BOLT';

แผนปฏิบัติการใหม่

ในแผนใหม่การแข่งขันกัญชามีไม่มีกริยาที่เหลือมีไม่มีตัวกรองที่ซับซ้อน , ไม่มีกริยาที่เหลือในมุมมองการจัดทำดัชนีแสวงหาและประมาณการ cardinalityถูกต้องว่า

เป็นตัวอย่างของวิธีการที่แทรก / ปรับปรุง / ลบแผนจะได้รับผลกระทบนี่คือแผนสำหรับการแทรกไปยังตาราง ItemTrans:

แทรกแผน

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

การSELECT * FROM viewทดสอบเดียวกันเสร็จสมบูรณ์ก่อนหน้านี้ใน 150ms โดยมีมุมมองที่ทำดัชนีไว้

สิ่งสุดท้าย: ฉันสังเกตเห็นว่าเซิร์ฟเวอร์ 2008 R2 ของคุณยังอยู่ที่ RTM มันจะไม่แก้ไขปัญหาประสิทธิภาพการทำงานของคุณ แต่Service Pack 2 สำหรับ 2008 R2พร้อมใช้งานตั้งแต่เดือนกรกฎาคม 2012 และมีเหตุผลที่ดีมากมายที่จะทำให้เป็นปัจจุบันที่สุดเท่าที่จะทำได้ด้วย Service Pack

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