ทำไมการเข้าร่วม cardinality นี้จึงมีขนาดใหญ่มาก?


18

ฉันกำลังประสบกับสิ่งที่ฉันคิดว่ามีค่าระดับความเป็นหัวใจสูงสำหรับการค้นหาต่อไปนี้:

SELECT dm.PRIMARY_ID
FROM
(
    SELECT COALESCE(d1.JOIN_ID, d2.JOIN_ID, d3.JOIN_ID) PRIMARY_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
) dm
INNER JOIN X_LAST_TABLE lst ON dm.PRIMARY_ID = lst.JOIN_ID;

แผนประมาณที่นี่ ฉันกำลังทำงานกับสำเนาสถิติของตารางดังนั้นฉันจึงไม่สามารถรวมแผนจริงได้ อย่างไรก็ตามฉันไม่คิดว่ามันจะเกี่ยวข้องกับปัญหานี้มากนัก

SQL Server ประมาณการว่าแถว 481577 จะถูกส่งคืนจากตารางที่ได้รับ "dm" จากนั้นประมาณว่า 4528030000 แถวจะถูกส่งคืนหลังจากดำเนินการเข้าร่วมกับ X_LAST_TABLE แต่ JOIN_ID เป็นคีย์หลักของ X_LAST_TIME ฉันคาดว่าจะมีค่าประมาณการเข้าร่วมระหว่าง 0 ถึง 481577 แต่ประมาณการแถวดูเหมือนจะเป็น 10% ของจำนวนแถวที่ฉันจะได้รับเมื่อข้ามเข้าร่วมตารางด้านนอกและด้านใน คณิตศาสตร์สำหรับการปัดเศษ: 481577 * 94025 * 0.1 = 45280277425 ซึ่งถูกปัดเศษเป็น 4528030000

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

ฉันกำลังทดสอบกับ Microsoft SQL Server 2014 โดยเปิดใช้งานตัวประมาณค่า cardinality ดั้งเดิม TF 4199 และอื่น ๆ เปิดอยู่ ฉันสามารถให้รายการเต็มของการตั้งค่าสถานะการติดตามหากที่เกี่ยวข้องกับการลงทะเบียน

นี่คือนิยามของตารางที่เกี่ยวข้องมากที่สุด:

CREATE TABLE X_LAST_TABLE (
JOIN_ID NUMERIC(18, 0) NOT NULL
    CONSTRAINT PK_X_LAST_TABLE PRIMARY KEY CLUSTERED (JOIN_ID ASC)
);

ฉันยังใช้สคริปต์สร้างตารางทั้งหมดพร้อมกับสถิติของพวกเขาหากใครต้องการทำซ้ำปัญหาบนเซิร์ฟเวอร์ตัวใดตัวหนึ่ง

ในการเพิ่มข้อสังเกตของฉันบางอย่างโดยใช้ TF 2312 จะแก้ไขการประมาณ แต่นั่นไม่ใช่ตัวเลือกสำหรับฉัน TF 2301 ไม่สามารถแก้ไขการประมาณได้ การลบตารางใดตารางหนึ่งจะแก้ไขการประมาณ น่าประหลาดใจที่การเปลี่ยนลำดับการเข้าร่วมของ X_DETAIL_LINK ยังแก้ไขการประมาณการ การเปลี่ยนลำดับการเข้าร่วมหมายถึงการเขียนคำค้นใหม่และไม่บังคับให้คำสั่งเข้าร่วมเป็นคำใบ้ นี่คือแผนแบบสอบถามโดยประมาณเมื่อเพิ่งเปลี่ยนลำดับการรวม


ป.ล. หากคุณสามารถสลับไปbigintใช้แทนได้decimal(18, 0)คุณจะได้รับประโยชน์: 1) ใช้ 8 ไบต์แทน 9 สำหรับทุกค่าและ 2) ใช้ชนิดข้อมูลที่เทียบเคียงได้แทนไบต์แทนที่จะเป็นประเภทข้อมูลที่อัดแน่นซึ่งอาจมีผลกระทบ สำหรับเวลา CPU เมื่อเปรียบเทียบค่า
ErikE

@ErikE ขอบคุณสำหรับเคล็ดลับ แต่ฉันรู้แล้วว่า น่าเสียดายที่เราติดกับ NUMERIC (18,0) มากกว่า BIGINT ด้วยเหตุผลดั้งเดิม
โจ Obbish

มันคุ้มค่ากับการยิง!
ErikE

คุณต้องการX_DETAIL2และX_DETAIL3ตารางทั้งหมดถ้าJOIN_IDไม่เป็นโมฆะX_DETAIL1?
ErikE

@ErikE นี่คือ MCVE ดังนั้นการค้นหาจึงไม่สมเหตุสมผลในขณะนี้
Joe Obbish

คำตอบ:


14

ฉันรู้ว่าการทำ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และกุญแจต่างประเทศและข้อ จำกัด อื่น ๆ ที่เป็นประโยชน์สำหรับการรวบรวมแบบสอบถาม


10

ฉันเชื่อว่าCompute Scalarผู้ประกอบการที่เกิดจากCOALESCE(d1.JOIN_ID, d2.JOIN_ID, d3.JOIN_ID)การเข้าร่วมX_LAST_TABLE.JOIN_IDเป็นสาเหตุของปัญหา อดีตสเกลาคำนวณได้รับยากที่จะเสียค่าใช้จ่ายได้อย่างถูกต้อง1 , 2

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

SELECT COALESCE(dm.d1ID, dm.d2ID, dm.d3ID)
FROM
(
    SELECT d1ID = d1.JOIN_ID
        , d2ID = d2.JOIN_ID
        , d3ID = 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
) dm
INNER JOIN X_LAST_TABLE lst 
    ON (dm.d1ID IS NOT NULL AND dm.d1ID = lst.JOIN_ID)
    OR (dm.d1ID IS NULL AND dm.d2ID IS NOT NULL AND dm.d2ID = lst.JOIN_ID)
    OR (dm.d1ID IS NULL AND dm.d2ID IS NULL AND dm.d3ID IS NOT NULL AND dm.d3ID = lst.JOIN_ID);

ในขณะที่xID IS NOT NULLไม่จำเป็นทางเทคนิคเนื่องจากID = JOIN_IDจะไม่เข้าร่วมกับค่า null ฉันรวมพวกเขาเพราะมันชัดเจน portrays เจตนา

แผน 1และแผน 2

แผน 1:

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

แผน 2:

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

แบบสอบถามแบบใหม่มีประโยชน์ (?) จากการขนาน นอกจากนี้ข้อสังเกตแบบสอบถามใหม่มีจำนวนผลลัพธ์ของการประมาณ 1 แถวซึ่งในความเป็นจริงอาจเลวร้ายลงในตอนท้ายของวันกว่าประมาณการของ 4528030000 สำหรับแบบสอบถามต้นฉบับ ค่าใช้จ่ายย่อยสำหรับผู้ประกอบการที่เลือกในแบบสอบถามใหม่มาที่ 243210 ในขณะที่นาฬิกาเดิมที่ 536.535 ซึ่งน้อยกว่าอย่างชัดเจน ต้องบอกว่าฉันไม่เชื่อว่าการประมาณการครั้งแรกอยู่ที่ใดก็ได้ใกล้เคียงกับความเป็นจริง


ภาคผนวก 1

หลังจากการปรึกษาหารือกับผู้คนในThe Heap ™มากขึ้นจากการพูดคุยกับ @Lamak ดูเหมือนว่าแบบสอบถามเชิงสังเกตการณ์ของฉันทำงานได้ดีมากแม้จะมีความเท่าเทียมกัน โซลูชันที่ให้ทั้งประสิทธิภาพที่ดีและการประเมิน cardinality ที่ดีประกอบด้วยการแทนที่COALESCE(x,y,z)ด้วยISNULL(ISNULL(x, y), z), ดังใน:

SELECT dm.PRIMARY_ID
FROM
(
    SELECT ISNULL(ISNULL(d1.JOIN_ID, d2.JOIN_ID), d3.JOIN_ID) PRIMARY_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
) dm
INNER JOIN X_LAST_TABLE lst ON dm.PRIMARY_ID = lst.JOIN_ID;

COALESCEถูกแปลงเป็นCASEคำสั่ง "ภายใต้หน้าปก" โดยเครื่องมือเพิ่มประสิทธิภาพข้อความค้นหา เช่นประมาณการ cardinality COALESCEมีช่วงเวลาที่ยากค้นพบสถิติที่เชื่อถือได้สำหรับคอลัมน์ฝังอยู่ภายใน ISNULLฟังก์ชั่นที่แท้จริงคือ "open" สำหรับตัวประมาณค่า cardinality นอกจากนี้ยังไม่มีค่าใด ๆ ที่ISNULLสามารถปรับให้เหมาะสมหากทราบว่าเป้าหมายไม่เป็นโมฆะ

แผนสำหรับISNULLชุดตัวเลือกมีลักษณะดังนี้:

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

(วางเวอร์ชันของ Plan ที่นี่ )

FYI ประกอบไปด้วยSentry Oneสำหรับ Plan Explorer ที่ยอดเยี่ยมของพวกเขาซึ่งฉันเคยทำแผนกราฟิกด้านบน


-1

ตามเงื่อนไขการเข้าร่วมของคุณตารางสามารถจัดเรียงในมารยาทมากมายนั่นคือ "การเปลี่ยนเป็นลักษณะเฉพาะ" แก้ไขผล

สมมติว่าการเข้าร่วมเพียงหนึ่งตารางให้ผลลัพธ์ที่ถูกต้อง

SELECT COALESCE(d1.JOIN_ID, d2.JOIN_ID, d3.JOIN_ID) PRIMARY_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

ที่นี่ในสถานที่ของX_DETAIL_1คุณสามารถใช้อย่างใดอย่างหนึ่งหรือX_DETAIL_2X_DETAIL_3

ดังนั้นจุดประสงค์ของการพัก 2 ตารางจึงไม่ชัดเจน

มันเหมือนกับว่าคุณแบ่งโต๊ะX_DETAIL_1ออกเป็นสองส่วน

ส่วนใหญ่อาจจะ " มีข้อผิดพลาดที่คุณจะเติมตารางเหล่านั้น. " นึกคิดX_DETAIL_1, X_DETAIL_2และX_DETAIL_3ควรมีจำนวนเท่ากับแถว

แต่อย่างน้อยหนึ่งตารางมีจำนวนแถวที่ไม่ต้องการ

ขออภัยถ้าฉันผิด

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