ฉันรู้ว่าการทำCOALESCE
ในสองสามคอลัมน์และเข้าร่วมกับพวกเขาไม่ใช่วิธีที่ดี
การสร้างความคาดหวังและการแจกแจงที่ดีนั้นทำได้ยากพอเมื่อสคีมาคือ 3NF + (พร้อมคีย์และข้อ จำกัด ) และเคียวรีนั้นสัมพันธ์กันและเป็นหลัก SPJG (ส่วนที่เลือกฉาย - เข้าร่วมกลุ่มโดย) โมเดล CE สร้างขึ้นบนหลักการเหล่านั้น ยิ่งมีคุณลักษณะที่ผิดปกติหรือไม่มีความสัมพันธ์มากเท่าไหร่ก็ยิ่งมีความใกล้ชิดมากขึ้นเท่านั้นที่จะเข้าใกล้ขอบเขตของความสำคัญและกรอบการเลือกเฉพาะที่สามารถจัดการได้ ไปไกลเกินไปและ CE จะให้ขึ้นและคาดเดา
ตัวอย่างของ MCVE ส่วนใหญ่คือ SPJ แบบง่าย (ไม่ใช่ G) แม้ว่าจะมี equijoins ภายนอกที่โดดเด่น (ซึ่งจำลองว่าเป็นการรวมภายในและการต่อต้านเซมินอิน) แทนที่จะเป็น equijoin ภายในที่ง่ายกว่า (หรือ semijoin) ความสัมพันธ์ทั้งหมดมีกุญแจแม้ว่าจะไม่มีกุญแจต่างประเทศหรือข้อ จำกัด อื่น ๆ ทั้งหมด แต่หนึ่งในการเข้าร่วมเป็นแบบหนึ่งต่อหลายคนซึ่งเป็นสิ่งที่ดี
ยกเว้นในกรณีที่เป็นหลายต่อหลายคนเข้าร่วม outer ระหว่างและX_DETAIL_1
X_DETAIL_LINK
ฟังก์ชั่นเพียงนี้เข้าร่วมใน MCVE X_DETAIL_1
เป็นแถวที่อาจเกิดขึ้นซ้ำกันใน นี่คือความผิดปกติการจัดเรียงของสิ่งที่
ภาคความเท่าเทียมง่าย ๆ (ตัวเลือก) และตัวดำเนินการสเกลาร์ก็ดีกว่าเช่นกัน ตัวอย่างเช่นคุณลักษณะ attribute-constant เปรียบเทียบ / คงที่ตามปกติทำงานได้ดีในรูปแบบ มันค่อนข้าง "ง่าย" ในการปรับเปลี่ยนฮิสโทแกรมและสถิติความถี่เพื่อสะท้อนการใช้งานของภาคแสดงดังกล่าว
COALESCE
ถูกสร้างขึ้นบนCASE
ซึ่งจะนำมาใช้ภายในเป็นIIF
(และนี่เป็นความจริงที่ดีก่อนที่จะIIF
ปรากฏในภาษา Transact-SQL) แบบจำลอง CE IIF
เหมือนกับเด็กUNION
สองคนซึ่งกันและกันโดยแต่ละโครงการประกอบด้วยโครงการเกี่ยวกับการคัดเลือกด้านความสัมพันธ์อินพุต ส่วนประกอบที่ระบุแต่ละรายการมีการสนับสนุนรูปแบบดังนั้นการรวมเข้าด้วยกันจึงค่อนข้างตรงไปตรงมา ถึงแม้ว่าเลเยอร์ abstractions จะยิ่งมีความแม่นยำน้อยกว่า แต่ผลลัพธ์ที่ได้ก็มีความแม่นยำน้อยกว่าซึ่งเป็นเหตุผลว่าทำไมแผนการดำเนินการที่ใหญ่กว่าจึงมีความเสถียรและเชื่อถือได้น้อยกว่า
ISNULL
ในทางกลับกันคือภายในเครื่องยนต์ มันไม่ได้สร้างขึ้นโดยใช้องค์ประกอบพื้นฐานใด ๆ เพิ่มเติม ISNULL
ยกตัวอย่างเช่นการใช้เอฟเฟกต์ของฮิสโตแกรมนั้นง่ายเหมือนการเปลี่ยนขั้นตอนสำหรับNULL
ค่า (และการบีบอัดตามความจำเป็น) มันยังคงค่อนข้างทึบเมื่อตัวดำเนินการสเกลาร์ไปและหลีกเลี่ยงที่ดีที่สุดถ้าเป็นไปได้ อย่างไรก็ตามโดยทั่วไปแล้วจะพูดง่ายขึ้นสำหรับเครื่องมือเพิ่มประสิทธิภาพ (เพิ่มประสิทธิภาพน้อยกว่า - ไม่เป็นมิตร) กว่าCASE
ทางเลือกอื่น
CE (70 และ 120+) นั้นซับซ้อนมากแม้ตามมาตรฐาน SQL Server ไม่ใช่กรณีของการใช้ตรรกะอย่างง่าย (พร้อมสูตรลับ) กับผู้ให้บริการแต่ละราย CE รู้เกี่ยวกับคีย์และการพึ่งพาการทำงาน มันรู้วิธีประมาณค่าโดยใช้ความถี่สถิติหลายตัวแปรและฮิสโตแกรม และมีกรณีพิเศษจำนวนมากการปรับแต่งการตรวจสอบและยอดคงเหลือและโครงสร้างสนับสนุน มักจะประมาณเช่นเข้าร่วมหลายวิธี (ความถี่ฮิสโตแกรม) และตัดสินใจเลือกผลลัพธ์หรือการปรับตามความแตกต่างระหว่างสองแบบ
สิ่งพื้นฐานสุดท้ายหนึ่งที่จะครอบคลุม: การประเมินค่าเริ่มต้นของ cardinality จะดำเนินการสำหรับทุกการดำเนินการในโครงสร้างคิวรีจากล่างขึ้นบน หัวกะทิและความเป็นหัวใจได้รับมาจากผู้ปฏิบัติงานใบไม้ก่อน (ความสัมพันธ์พื้นฐาน) ฮิสโตแกรมที่ได้รับการดัดแปลงและข้อมูลความหนาแน่น / ความถี่ได้รับมาจากผู้ประกอบการหลัก ยิ่งเราเดินไปได้ไกลเท่าไหร่คุณภาพของการประเมินก็จะลดลงตามความผิดพลาดที่เกิดขึ้น
การประเมินแบบครอบคลุมเริ่มต้นเดียวนี้เป็นจุดเริ่มต้นและเกิดขึ้นได้ดีก่อนที่จะมีการพิจารณาแผนการดำเนินการขั้นสุดท้าย แผนผังคิวรี ณ จุดนี้มีแนวโน้มที่จะสะท้อนรูปแบบการเขียนของเคียวรีอย่างใกล้ชิด (แม้ว่าจะมีการลบเคียวรีย่อยและการประยุกต์ใช้การทำให้เข้าใจง่ายเป็นต้น)
ทันทีหลังจากการประมาณค่าเริ่มต้น SQL Server จะทำการจัดเรียงฮิวริสติกการเรียงลำดับใหม่ซึ่งพูดอย่างหลวม ๆ พยายามที่จะจัดลำดับใหม่ของต้นไม้เพื่อวางตารางที่เล็กลง นอกจากนี้ยังพยายามจัดตำแหน่งการรวมภายในก่อนเข้าร่วมด้านนอกและข้ามผลิตภัณฑ์ ความสามารถของมันยังไม่ครอบคลุม ความพยายามของมันไม่ครบถ้วนสมบูรณ์ และจะไม่พิจารณาค่าใช้จ่ายทางกายภาพ (เนื่องจากยังไม่มีข้อมูลทางสถิติและข้อมูลเมตาดาต้าเท่านั้นที่มีอยู่) การจัดลำดับแบบฮิวริสติกนั้นประสบความสำเร็จมากที่สุดบนต้น Equijoin ด้านใน มีอยู่เพื่อให้เป็นจุดเริ่มต้น "ดีกว่า" สำหรับการเพิ่มประสิทธิภาพตามต้นทุน
ทำไมการเข้าร่วม cardinality นี้จึงมีขนาดใหญ่มาก?
MCVE มีการเข้าร่วมแบบ "ต่อเนื่อง" ที่ผิดปกติซึ่งส่วนใหญ่ต่อหลายคนและการเข้าร่วม equi COALESCE
ในภาคแสดง แผนผังโอเปอเรเตอร์ยังมีการเข้าร่วมภายในครั้งล่าสุดซึ่งการจัดลำดับการเข้าร่วมแบบฮิวริสติกไม่สามารถเลื่อนต้นไม้ขึ้นไปยังตำแหน่งที่ต้องการได้อีก ออกจากสเกลาร์และการคาดการณ์ทั้งหมดต้นไม้เข้าร่วมคือ:
LogOp_Join [ Card=4.52803e+009 ]
LogOp_LeftOuterJoin [ Card=481577 ]
LogOp_LeftOuterJoin [ Card=481577 ]
LogOp_LeftOuterJoin [ Card=481577 ]
LogOp_LeftOuterJoin [ Card=481577 ]
LogOp_Get TBL: X_DRIVING_TABLE(alias TBL: dt) [ Card=481577 ]
LogOp_Get TBL: X_DETAIL_1(alias TBL: d1) [ Card=70 ]
LogOp_Get TBL: X_DETAIL_LINK(alias TBL: lnk) [ Card=47 ]
LogOp_Get TBL: X_DETAIL_2(alias TBL: d2) X_DETAIL_2 [ Card=119 ]
LogOp_Get TBL: X_DETAIL_3(alias TBL: d3) X_DETAIL_3 [ Card=281 ]
LogOp_Get TBL: X_LAST_TABLE(alias TBL: lst) X_LAST_TABLE [ Card=94025 ]
โปรดทราบว่าการประมาณการขั้นสุดท้ายที่ผิดพลาดเกิดขึ้นแล้ว มันถูกพิมพ์เป็นCard=4.52803e+009
และเก็บไว้ภายในเป็นค่าทศนิยมความแม่นยำสองครั้งที่ 4.5280277425e + 9 (4528027742.5 เป็นทศนิยม)
ตารางที่ได้รับในแบบสอบถามต้นฉบับได้ถูกลบออกและการคาดการณ์จะทำให้เป็นมาตรฐาน การแทนค่า SQL ของทรีที่ดำเนินการประมาณค่าเริ่มต้นและการเลือกจำเพาะคือ:
SELECT
PRIMARY_ID = COALESCE(d1.JOIN_ID, d2.JOIN_ID, d3.JOIN_ID)
FROM X_DRIVING_TABLE dt
LEFT OUTER JOIN X_DETAIL_1 d1
ON dt.ID = d1.ID
LEFT OUTER JOIN X_DETAIL_LINK lnk
ON d1.LINK_ID = lnk.LINK_ID
LEFT OUTER JOIN X_DETAIL_2 d2
ON dt.ID = d2.ID
LEFT OUTER JOIN X_DETAIL_3 d3
ON dt.ID = d3.ID
INNER JOIN X_LAST_TABLE lst
ON lst.JOIN_ID = COALESCE(d1.JOIN_ID, d2.JOIN_ID, d3.JOIN_ID)
(นอกเหนือจากนั้นการทำซ้ำCOALESCE
จะปรากฏในแผนสุดท้าย - หนึ่งครั้งในการคำนวณสเกลาร์ครั้งสุดท้ายและอีกครั้งที่ด้านในของการเข้าร่วมภายใน)
สังเกตเห็นการเข้าร่วมขั้นสุดท้าย การรวมภายในนี้คือ (ตามคำนิยาม) ผลิตภัณฑ์คาร์ทีเซียนของX_LAST_TABLE
และผลลัพธ์การรวมก่อนหน้าพร้อมกับการเลือก (รวมภาคแสดง) ของlst.JOIN_ID = COALESCE(d1.JOIN_ID, d2.JOIN_ID, d3.JOIN_ID)
การนำไปใช้ ความสำคัญของผลิตภัณฑ์คาร์ทีเซียนคือ 481577 * 94025 = 45280277425
เพื่อที่เราจะต้องกำหนดและใช้การเลือกของภาคแสดง การรวมกันของCOALESCE
ต้นไม้ขยายทึบ(ในแง่ของUNION
และIIF
จำได้) พร้อมกับผลกระทบต่อข้อมูลที่สำคัญฮิสโทแกรมและความถี่ที่ได้รับจาก "ผิดปกติ" ก่อนหน้านี้ส่วนใหญ่ - ซ้ำซ้อนหลายต่อหลายด้านรวมเข้าด้วยกันหมายความว่า CE ไม่สามารถ รับการประมาณค่าที่ยอมรับได้ในวิธีการปกติ
เป็นผลให้มันเข้าสู่ Guess Logic ตรรกะการเดามีความซับซ้อนปานกลางโดยมีเลเยอร์ของการเดาแบบ "มีการศึกษา" และ "อัลกอริธึมการเดา" ที่ไม่ได้รับการศึกษา " หากไม่พบพื้นฐานที่ดีกว่าสำหรับการคาดเดาโมเดลจะใช้การเดาสุดท้ายซึ่งสำหรับการเปรียบเทียบความเท่าเทียมกันคือ: sqllang!x_Selectivity_Equal
= การเลือกจำเพาะคงที่ 0.1 (คาดเดา 10%):
-- the moment of doom
movsd xmm0,mmword ptr [sqllang!x_Selectivity_Equal
ผลลัพธ์คือ 0.1 การเลือกในผลิตภัณฑ์คาร์ทีเซียน: 481577 * 94025 * 0.1 = 4528027742.5 (~ 4.52803e + 009) ตามที่กล่าวไว้ก่อนหน้านี้
เขียนใหม่
เมื่อการรวมที่มีปัญหาถูกใส่ความคิดเห็นออกการประเมินที่ดีกว่าจะเกิดขึ้นเนื่องจากการหลีกเลี่ยงการเลือก "เดาทางเลือกสุดท้าย" คงที่ (ข้อมูลสำคัญถูกเก็บไว้โดยการรวม 1-M) คุณภาพของการประเมินนั้นยังคงมีความเชื่อมั่นต่ำเนื่องจากเพรดิเคตการCOALESCE
เข้าร่วมนั้นไม่ได้เป็นมิตรกับ CE เลย การประมาณการที่แก้ไขอย่างน้อยก็ดูสมเหตุสมผลกับมนุษย์ฉันคิดว่า
เมื่อมีการเขียนแบบสอบถามด้วยการรวมภายนอกเพื่อX_DETAIL_LINK
วางไว้ที่อันดับสุดท้ายการจัดลำดับแบบฮิวริสติกสามารถสลับกับการรวมภายในเป็นครั้งสุดท้ายX_LAST_TABLE
ได้ การวางการรวมภายในไว้ข้างๆปัญหาการเข้าร่วมด้านนอกทำให้ความสามารถที่ จำกัด ของการเรียงลำดับใหม่มีโอกาสที่จะปรับปรุงการประเมินขั้นสุดท้ายเนื่องจากผลของการเข้าร่วมด้านนอกแบบหลายต่อหลายครั้งส่วนใหญ่ผิดปกติมาหลังจากการประมาณค่าการเลือกหัวเลี้ยว COALESCE
สำหรับ อีกครั้งการประมาณการดีกว่าการคาดเดาคงที่เพียงเล็กน้อยและอาจจะไม่ยืนขึ้นเพื่อพิจารณาการไต่สวนในศาล
การจัดเรียงใหม่ของการรวมภายในและภายนอกเข้าด้วยกันนั้นยากและใช้เวลานาน (แม้กระทั่งการเพิ่มประสิทธิภาพขั้นที่ 2 แม้เพียงแค่พยายาม จำกัด ชุดย่อยของการเคลื่อนไหวตามทฤษฎี)
ISNULL
ข้อเสนอแนะที่ซ้อนกันในคำตอบของ Max Vernon ช่วยให้หลีกเลี่ยงการคาดเดาการประกันตัวได้คงที่ แต่การประเมินขั้นสุดท้ายคือแถวศูนย์ที่ไม่น่าจะเป็นไปได้ (ยกขึ้นเป็นหนึ่งแถวเพื่อความเหมาะสม) นี่อาจเป็นการเดาที่แน่นอนของ 1 แถวสำหรับพื้นฐานทางสถิติทั้งหมดที่การคำนวณมี
ฉันคาดว่าจะมีค่าประมาณการเข้าร่วมระหว่าง 0 ถึง 481577
นี่เป็นความคาดหวังที่สมเหตุสมผลแม้ว่าใคร ๆ จะยอมรับว่าการประเมินเชิงหัวใจสามารถเกิดขึ้นได้ในเวลาที่ต่างกัน (ในระหว่างการปรับให้เหมาะสมตามต้นทุน) กับความแตกต่างทางร่างกาย แต่ทรีย่อยที่เหมือนกันทั้งทางตรรกะและเชิงความหมาย ดีที่สุด (ต่อกลุ่มบันทึก) การขาดการรับประกันความสอดคล้องทั่วทั้งแผนไม่ได้หมายความว่าการเข้าร่วมเป็นรายบุคคลควรจะสามารถทำให้เกิดความน่าเชื่อถือได้
ในทางกลับกันถ้าเราจบลงด้วยการคาดเดาสุดท้ายหวังว่าจะหายไปแล้วทำไมต้องรำคาญ เราลองใช้เทคนิคทั้งหมดที่เรารู้และยอมแพ้ หากไม่มีอะไรอื่นการคาดคะเนขั้นสุดท้ายที่ดุเดือดเป็นสัญญาณเตือนภัยที่ยอดเยี่ยมว่าทุกอย่างไม่ได้ไปได้ดีภายใน CE ในระหว่างการรวบรวมและเพิ่มประสิทธิภาพของการสืบค้นนี้
เมื่อฉันลองใช้ MCVE, 120+ CE สร้างการประเมินขั้นสุดท้ายแถวศูนย์ (= 1) แถว (เช่นซ้อนกันISNULL
) สำหรับการค้นหาดั้งเดิมซึ่งไม่เป็นที่ยอมรับตามวิธีการคิดของฉัน
โซลูชันที่แท้จริงอาจเกี่ยวข้องกับการเปลี่ยนแปลงการออกแบบเพื่ออนุญาตให้มีการรวมแบบง่ายโดยไม่ต้องCOALESCE
หรือISNULL
และกุญแจต่างประเทศและข้อ จำกัด อื่น ๆ ที่เป็นประโยชน์สำหรับการรวบรวมแบบสอบถาม
bigint
ใช้แทนได้decimal(18, 0)
คุณจะได้รับประโยชน์: 1) ใช้ 8 ไบต์แทน 9 สำหรับทุกค่าและ 2) ใช้ชนิดข้อมูลที่เทียบเคียงได้แทนไบต์แทนที่จะเป็นประเภทข้อมูลที่อัดแน่นซึ่งอาจมีผลกระทบ สำหรับเวลา CPU เมื่อเปรียบเทียบค่า