แผนดังกล่าวถูกคอมไพล์บนอินสแตนซ์ RTM ของ SQL Server 2008 R2 (รุ่น 10.50.1600) คุณควรติดตั้งService Pack 3 (บิวด์ 10.50.6000) ตามด้วยแพทช์ล่าสุดเพื่อนำไปสู่การสร้างล่าสุด (ปัจจุบัน) 10.50.6542 สิ่งนี้มีความสำคัญด้วยเหตุผลหลายประการรวมถึงความปลอดภัยการแก้ไขข้อบกพร่องและคุณสมบัติใหม่
การเพิ่มประสิทธิภาพการฝังพารามิเตอร์
เกี่ยวข้องกับคำถามปัจจุบัน SQL Server 2008 R2 RTM ไม่สนับสนุนพารามิเตอร์ฝัง Optimization (PEO) OPTION (RECOMPILE)
สำหรับ ตอนนี้คุณกำลังจ่ายค่าใช้จ่ายในการคอมไพล์ซ้ำโดยไม่คำนึงถึงประโยชน์หลักอย่างใดอย่างหนึ่ง
เมื่อ PEO พร้อมใช้งาน SQL Server สามารถใช้ค่าตามตัวอักษรที่เก็บไว้ในตัวแปรและพารามิเตอร์ภายในเครื่องโดยตรงในแผนคิวรี สิ่งนี้สามารถนำไปสู่ความเรียบง่ายอย่างมากและเพิ่มประสิทธิภาพ มีข้อมูลเพิ่มเติมเกี่ยวกับว่าในบทความของฉัน, พารามิเตอร์ดมฝังและตัวเลือก RECOMPILE
Hash, Sort และ Exchange Spills
สิ่งเหล่านี้จะแสดงเฉพาะในแผนการดำเนินการเมื่อมีการรวบรวมแบบสอบถามใน SQL Server 2012 หรือใหม่กว่า ในรุ่นก่อนหน้านี้เราต้องตรวจสอบการรั่วไหลในขณะที่แบบสอบถามกำลังดำเนินการโดยใช้ Profiler หรือ Extended Events การรั่วไหลส่งผลให้ I / O ทางกายภาพไปยัง (และจาก) หน่วยเก็บข้อมูลสำรองถาวรtempdbซึ่งสามารถมีผลการทำงานที่สำคัญโดยเฉพาะอย่างยิ่งหากการรั่วไหลมีขนาดใหญ่หรือเส้นทาง I / O อยู่ภายใต้แรงกดดัน
ในแผนการดำเนินการของคุณมีตัวดำเนินการแฮช (รวม) สองตัว หน่วยความจำที่สงวนไว้สำหรับตารางแฮชจะขึ้นอยู่กับการประมาณการสำหรับแถวเอาท์พุท (กล่าวอีกนัยหนึ่งมันเป็นสัดส่วนกับจำนวนกลุ่มที่พบที่รันไทม์) หน่วยความจำที่ได้รับจะได้รับการแก้ไขก่อนที่จะมีการเรียกใช้งานและไม่สามารถเติบโตได้ในระหว่างการดำเนินการไม่ว่าหน่วยความจำนั้นจะมีจำนวนเท่าใดก็ตาม ในแผนที่ให้มาตัวดำเนินการแฮชทั้งคู่ (รวม) ผลิตแถวมากกว่าที่เครื่องมือเพิ่มประสิทธิภาพที่คาดไว้และอาจประสบปัญหาการหกถึงtempdbขณะใช้งานจริง
นอกจากนี้ยังมีโอเปอเรเตอร์แฮช (Inner Join) ในแผน หน่วยความจำที่สงวนไว้สำหรับตารางแฮชจะขึ้นอยู่กับการประมาณการสำหรับแถวป้อนข้อมูลด้านการสอบสวน โพรบอินพุตประมาณการประมาณ 847,399 แถว แต่พบ 1,223,636 ในขณะใช้งาน ส่วนเกินนี้อาจเป็นสาเหตุของการรั่วไหลของกัญชา
การรวมซ้ำซ้อน
การจับคู่แฮช (รวม) ที่โหนด 8 ทำการดำเนินการจัดกลุ่มบน(Assortment_Id, CustomAttrID)
แต่แถวอินพุตเท่ากับแถวเอาต์พุต:
สิ่งนี้แสดงให้เห็นว่าการรวมกันของคอลัมน์เป็นกุญแจสำคัญ (ดังนั้นการจัดกลุ่มจึงไม่จำเป็นต้องใช้ความหมาย) ค่าใช้จ่ายในการดำเนินการรวมซ้ำซ้อนจะเพิ่มขึ้นตามความต้องการผ่าน 1.4 ล้านแถวสองครั้งในการแลกเปลี่ยนการแบ่งพาร์ติชันแบบแฮช
เนื่องจากคอลัมน์ที่เกี่ยวข้องมาจากตารางที่แตกต่างกันมันเป็นเรื่องยากกว่าปกติในการสื่อสารข้อมูลที่เป็นเอกลักษณ์นี้ไปยังเครื่องมือเพิ่มประสิทธิภาพดังนั้นจึงสามารถหลีกเลี่ยงการดำเนินการจัดกลุ่มซ้ำซ้อนและการแลกเปลี่ยนที่ไม่จำเป็น
การกระจายเธรดที่ไม่มีประสิทธิภาพ
ตามที่ระบุไว้ใน คำตอบของ Joe Obbishการแลกเปลี่ยนที่โหนด 14 ใช้การแบ่งแฮชเพื่อกระจายแถวระหว่างเธรด น่าเสียดายที่จำนวนแถวและตัวจัดตารางเวลาที่มีอยู่น้อยหมายความว่าทั้งสามแถวจะสิ้นสุดในเธรดเดี่ยว เห็นได้ชัดว่าแผนขนานวิ่งตามลำดับ (มีค่าใช้จ่ายขนาน) เท่าที่การแลกเปลี่ยนที่โหนด 9
คุณสามารถระบุสิ่งนี้ (เพื่อรับการปัดเศษแบบแบ่งรอบหรือการแบ่งพาร์ทิชันแบบกระจาย) โดยกำจัด Distinct Sort ที่โหนด 13 วิธีที่ง่ายที่สุดคือการสร้างคีย์หลักแบบคลัสเตอร์บน#temp
ตารางและทำการดำเนินการที่แตกต่างกันเมื่อโหลดตาราง:
CREATE TABLE #Temp
(
id integer NOT NULL PRIMARY KEY CLUSTERED
);
INSERT #Temp
(
id
)
SELECT DISTINCT
CAV.id
FROM @customAttrValIds AS CAV
WHERE
CAV.id IS NOT NULL;
การแคชสถิติตารางชั่วคราว
แม้จะมีการใช้งานOPTION (RECOMPILE)
SQL Server ยังคงสามารถแคชวัตถุตารางชั่วคราวและสถิติที่เกี่ยวข้องระหว่างการเรียกกระบวนงาน นี่คือการเพิ่มประสิทธิภาพประสิทธิภาพการต้อนรับโดยทั่วไป แต่ถ้าตารางชั่วคราวถูกเติมด้วยจำนวนข้อมูลที่คล้ายกันในการเรียกโพรซีเดอร์ที่อยู่ติดกันแผน recompiled อาจขึ้นอยู่กับสถิติที่ไม่ถูกต้อง (แคชจากการดำเนินการก่อนหน้านี้) นี่คือรายละเอียดในบทความของฉันตารางชั่วคราวในขั้นตอนการจัดเก็บและตารางแคชชั่วคราวอธิบายชั่วคราวตารางแคชอธิบาย
เพื่อหลีกเลี่ยงปัญหานี้ให้ใช้OPTION (RECOMPILE)
ร่วมกับอย่างชัดเจนUPDATE STATISTICS #TempTable
หลังจากเติมข้อมูลตารางชั่วคราวและก่อนที่จะมีการอ้างอิงในแบบสอบถาม
เขียนแบบสอบถามใหม่
ส่วนนี้จะถือว่าการเปลี่ยนแปลงการสร้าง #Temp
ตารางได้ทำไปแล้ว
เมื่อพิจารณาถึงค่าใช้จ่ายของการรั่วไหลของแฮชที่เป็นไปได้และการรวมซ้ำซ้อน (และการแลกเปลี่ยนโดยรอบ) อาจจ่ายให้เป็นรูปธรรมที่โหนด 10
CREATE TABLE #Temp2
(
CustomAttrID integer NOT NULL,
Assortment_Id integer NOT NULL,
);
INSERT #Temp2
(
Assortment_Id,
CustomAttrID
)
SELECT
ACAV.Assortment_Id,
CAV.CustomAttrID
FROM #temp AS T
JOIN dbo.CustomAttributeValues AS CAV
ON CAV.Id = T.id
JOIN dbo.AssortmentCustomAttributeValues AS ACAV
ON T.id = ACAV.CustomAttributeValue_Id;
ALTER TABLE #Temp2
ADD CONSTRAINT PK_#Temp2_Assortment_Id_CustomAttrID
PRIMARY KEY CLUSTERED (Assortment_Id, CustomAttrID);
PRIMARY KEY
จะถูกเพิ่มในขั้นตอนที่แยกต่างหากเพื่อให้แน่ใจว่าดัชนีสร้างได้ข้อมูลที่ถูกต้อง cardinality และเพื่อหลีกเลี่ยงสถิติตารางชั่วคราวแคชปัญหา
การทำให้เป็นรูปธรรมนี้มีแนวโน้มที่จะเกิดขึ้นในหน่วยความจำ (หลีกเลี่ยงtempdb I / O) หากอินสแตนซ์มีหน่วยความจำเพียงพอ นี่คือแนวโน้มที่มากยิ่งขึ้นเมื่อคุณปรับรุ่นเป็น SQL Server 2012 (SP1 CU10 / SP2 CU1 หรือหลังจากนั้น) ซึ่งได้มีการปรับปรุงพฤติกรรมเขียนกระตือรือร้น
การกระทำนี้ให้ข้อมูลความถูกต้องของเครื่องมือเพิ่มประสิทธิภาพที่แม่นยำของชุดสื่อกลางช่วยให้สามารถสร้างสถิติและช่วยให้เราสามารถประกาศ(Assortment_Id, CustomAttrID)
เป็นกุญแจสำคัญได้
แผนสำหรับประชากร#Temp2
ควรมีลักษณะเช่นนี้ (หมายเหตุการสแกนดัชนีแบบกลุ่มของ#Temp
ไม่มีการเรียงที่แตกต่างและการแลกเปลี่ยนตอนนี้ใช้การแบ่งพาร์ติชันแถวแบบโรบิน):
ด้วยชุดที่พร้อมใช้งานแบบสอบถามสุดท้ายกลายเป็น:
SELECT
A.Id,
A.AssortmentId
FROM
(
SELECT
T.Assortment_Id
FROM #Temp2 AS T
GROUP BY
T.Assortment_Id
HAVING
COUNT_BIG(DISTINCT T.CustomAttrID) = @dist_ca_id
) AS DT
JOIN dbo.Assortments AS A
ON A.Id = DT.Assortment_Id
WHERE
A.AssortmentType = @asType
OPTION (RECOMPILE);
เราสามารถเขียนสิ่งCOUNT_BIG(DISTINCT...
ที่เรียบง่ายได้ด้วยตนเองCOUNT_BIG(*)
แต่ด้วยข้อมูลสำคัญใหม่ตัวเพิ่มประสิทธิภาพนั้นทำเพื่อเรา:
แผนขั้นสุดท้ายอาจใช้การเข้าร่วมวนรอบ / แฮช / การผสานขึ้นอยู่กับข้อมูลสถิติเกี่ยวกับข้อมูลที่ฉันไม่สามารถเข้าถึงได้ อีกหนึ่งบันทึกย่อขนาดเล็กอื่น ๆ : ฉันสันนิษฐานว่ามีดัชนีเช่นนี้CREATE [UNIQUE?] NONCLUSTERED INDEX IX_ ON dbo.Assortments (AssortmentType, Id, AssortmentId);
อยู่
อย่างไรก็ตามสิ่งที่สำคัญเกี่ยวกับแผนสุดท้ายคือการประเมินควรดีกว่ามากและลำดับการดำเนินการจัดกลุ่มที่ซับซ้อนได้ลดลงเป็นสตรีมรวมเดียว (ซึ่งไม่ต้องการหน่วยความจำจึงไม่สามารถกระจายไปยังดิสก์)
เป็นการยากที่จะบอกว่าประสิทธิภาพจะดีขึ้นจริง ๆในกรณีนี้ด้วยตารางชั่วคราวพิเศษ แต่การประมาณการและตัวเลือกแผนจะยืดหยุ่นได้มากขึ้นต่อการเปลี่ยนแปลงของปริมาณข้อมูลและการกระจายตลอดเวลา ซึ่งอาจมีค่ามากกว่าในระยะยาวมากกว่าการเพิ่มขึ้นเล็กน้อยในวันนี้ ไม่ว่าในกรณีใดตอนนี้คุณจะมีข้อมูลมากขึ้นสำหรับการตัดสินใจขั้นสุดท้ายของคุณ
#temp
สร้างและการใช้งานจะเป็นปัญหาสำหรับประสิทธิภาพไม่ใช่ผลกำไร คุณกำลังบันทึกลงในตารางที่ไม่ได้จัดทำดัชนีไว้เพื่อใช้ครั้งเดียวเท่านั้น ลองลบออกอย่างสมบูรณ์ (และอาจเปลี่ยนin (select id from #temp)
เป็นexists
แบบสอบถามย่อย