ทำไมการเปลี่ยนลำดับคอลัมน์การประกาศที่ประกาศจึงแนะนำการเรียงลำดับ


40

ฉันมีสองตารางที่มีชื่อคอลัมน์พิมพ์และดัชนีคีย์เหมือนกัน หนึ่งในพวกเขามีที่ไม่ซ้ำกันดัชนีคลัสเตอร์ที่หนึ่ง ๆ มีที่ไม่ซ้ำกัน

การตั้งค่าการทดสอบ

สคริปต์การตั้งค่ารวมถึงสถิติที่เป็นจริง:

DROP TABLE IF EXISTS #left;
DROP TABLE IF EXISTS #right;

CREATE TABLE #left (
    a       char(4) NOT NULL,
    b       char(2) NOT NULL,
    c       varchar(13) NOT NULL,
    d       bit NOT NULL,
    e       char(4) NOT NULL,
    f       char(25) NULL,
    g       char(25) NOT NULL,
    h       char(25) NULL
    --- and a few other columns
);

CREATE UNIQUE CLUSTERED INDEX IX ON #left (a, b, c, d, e, f, g, h)

UPDATE STATISTICS #left WITH ROWCOUNT=63800000, PAGECOUNT=186000;

CREATE TABLE #right (
    a       char(4) NOT NULL,
    b       char(2) NOT NULL,
    c       varchar(13) NOT NULL,
    d       bit NOT NULL,
    e       char(4) NOT NULL,
    f       char(25) NULL,
    g       char(25) NOT NULL,
    h       char(25) NULL
    --- and a few other columns
);

CREATE CLUSTERED INDEX IX ON #right (a, b, c, d, e, f, g, h)

UPDATE STATISTICS #right WITH ROWCOUNT=55700000, PAGECOUNT=128000;

ความผิดพลาด

เมื่อฉันเข้าร่วมสองตารางเหล่านี้ในคีย์การจัดกลุ่มของพวกเขาฉันคาดว่าการรวม MERGE แบบหนึ่งต่อหลายคนเป็นเช่นนี้:

SELECT *
FROM #left AS l
LEFT JOIN #right AS r ON
    l.a=r.a AND
    l.b=r.b AND
    l.c=r.c AND
    l.d=r.d AND
    l.e=r.e AND
    l.f=r.f AND
    l.g=r.g AND
    l.h=r.h
WHERE l.a='2018';

นี่คือแผนแบบสอบถามที่ฉันต้องการ:

นี่คือสิ่งที่ฉันต้องการ

(ไม่เป็นไรคำเตือนพวกเขาต้องทำกับสถิติปลอม)

อย่างไรก็ตามหากฉันเปลี่ยนลำดับของคอลัมน์ในการเข้าร่วมเช่น:

SELECT *
FROM #left AS l
LEFT JOIN #right AS r ON
    l.c=r.c AND     -- used to be third
    l.a=r.a AND     -- used to be first
    l.b=r.b AND     -- used to be second
    l.d=r.d AND
    l.e=r.e AND
    l.f=r.f AND
    l.g=r.g AND
    l.h=r.h
WHERE l.a='2018';

... สิ่งนี้เกิดขึ้น:

แผนแบบสอบถามหลังจากเปลี่ยนลำดับคอลัมน์ที่ประกาศในการเข้าร่วม

ตัวดำเนินการเรียงลำดับดูเหมือนว่าจะเรียงลำดับสตรีมตามลำดับที่ประกาศของการเข้าร่วมนั่นคือc, a, b, d, e, f, g, hเพิ่มการดำเนินการบล็อกในแผนคิวรีของฉัน

สิ่งที่ฉันได้ดู

  • ฉันลองเปลี่ยนคอลัมน์เป็นNOT NULLผลลัพธ์เดียวกัน
  • สร้างตารางต้นฉบับด้วยANSI_PADDING OFFแต่การสร้างด้วยANSI_PADDING ONไม่มีผลกับแผนนี้
  • ฉันลองINNER JOINแทนLEFT JOINไม่มีการเปลี่ยนแปลง
  • ฉันค้นพบมันใน 2014 SP2 Enterprise สร้างตัวแทนบน 2017 Developer (CU ปัจจุบัน)
  • การลบส่วนคำสั่ง WHERE ในคอลัมน์ดัชนีชั้นนำจะสร้างแผนที่ดี แต่มันจะมีผลต่อผลลัพธ์ .. :)

ในที่สุดเราก็มาถึงคำถาม

  • มันตั้งใจหรือไม่
  • ฉันสามารถกำจัดการเรียงลำดับโดยไม่ต้องเปลี่ยนการสืบค้น (ซึ่งเป็นรหัสผู้ขายได้หรือไม่ดังนั้นฉันจึงค่อนข้างไม่ ... ) ฉันสามารถเปลี่ยนตารางและดัชนีได้

คำตอบ:


28

มันตั้งใจหรือไม่

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

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

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

ตัวอย่างเช่นการเรียงลำดับสามารถหลีกเลี่ยงได้ง่ายๆโดยการจับคู่ข้อกำหนดการสั่งซื้อ (เช่นระดับบนสุดORDER BY) กับดัชนีที่มีอยู่ ในกรณีของคุณเล็กน้อยที่อาจหมายถึงการเพิ่มORDER BY l.a, l.b, l.c, l.d, l.e, l.f, l.g, l.h;แต่นี่เป็นการทำให้เข้าใจง่ายเกินไป (และยอมรับไม่ได้เพราะคุณไม่ต้องการเปลี่ยนแบบสอบถาม)

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

ในกรณีของคุณโดยเฉพาะใช่คุณอาจปรับการจัดทำดัชนีตาม jadarnel27 แนะนำให้หลีกเลี่ยงการเรียงลำดับ แม้ว่าจะมีเหตุผลเพียงเล็กน้อยที่ต้องการรวมการเข้าร่วมที่นี่จริง ๆ คุณสามารถบอกใบ้ทางเลือกระหว่างการแฮชหรือลูปการเข้าร่วมทางกายภาพด้วยการOPTION(HASH JOIN, LOOP JOIN)ใช้ Guide Plan โดยไม่ต้องเปลี่ยนเคียวรีขึ้นอยู่กับความรู้ของข้อมูลและการแลกเปลี่ยนระหว่างประสิทธิภาพที่ดีที่สุดเลวร้ายที่สุดและโดยเฉลี่ย

ในที่สุดในฐานะที่เป็นผู้อยากรู้อยากเห็นโปรดทราบว่าการเรียงลำดับสามารถหลีกเลี่ยงได้ด้วยวิธีง่าย ๆORDER BY l.bด้วยค่าใช้จ่ายของการผสานหลายต่อหลายกลุ่มที่อาจมีประสิทธิภาพน้อยกว่าเข้าด้วยกันโดยbลำพังด้วยส่วนที่เหลือที่ซับซ้อน ฉันพูดถึงสิ่งนี้เป็นภาพประกอบของการทำงานร่วมกันระหว่างคุณลักษณะของเครื่องมือเพิ่มประสิทธิภาพที่ฉันกล่าวถึงก่อนหน้านี้และวิธีที่ความต้องการระดับสูงสุดสามารถเผยแพร่ได้


19

ฉันสามารถกำจัดการเรียงลำดับโดยไม่ต้องเปลี่ยนการสืบค้น (ซึ่งเป็นรหัสผู้ขายได้หรือไม่ดังนั้นฉันจึงค่อนข้างไม่ ... ) ฉันสามารถเปลี่ยนตารางและดัชนีได้

หากคุณสามารถเปลี่ยนดัชนีได้ให้เปลี่ยนลำดับของดัชนี#rightเพื่อให้ตรงกับลำดับของตัวกรองในการเข้าร่วมจะลบการเรียงลำดับ (สำหรับฉัน):

CREATE CLUSTERED INDEX IX ON #right (c, a, b, d, e, f, g, h)

น่าประหลาดใจ (สำหรับฉันอย่างน้อย) ผลลัพธ์นี้ทำให้ไม่มีการค้นหาที่ลงท้ายด้วยการเรียงลำดับ

มันตั้งใจหรือไม่

เมื่อดูผลลัพธ์จากแฟล็กการติดตามแปลก ๆมีความแตกต่างที่น่าสนใจในโครงสร้างบันทึกขั้นสุดท้าย:

สกรีนช็อตของโครงสร้างบันทึกสุดท้ายสำหรับแต่ละแบบสอบถาม

ดังที่คุณเห็นใน "กลุ่มรูท" ที่ด้านบนทั้งสองเคียวรีมีตัวเลือกที่จะใช้การผสานเข้าร่วมเป็นการดำเนินการทางกายภาพหลักเพื่อดำเนินการค้นหานี้

แบบสอบถามที่ดี

การเข้าร่วมที่ไม่มีการเรียงลำดับนั้นขับเคลื่อนโดยกลุ่ม 29 ตัวเลือก 1 และกลุ่ม 31 ตัวเลือก 1 (ซึ่งแต่ละกลุ่มจะสแกนช่วงบนดัชนีที่เกี่ยวข้อง) มันถูกกรองโดยกลุ่ม 27 (ไม่แสดง) ซึ่งเป็นชุดของการเปรียบเทียบเชิงตรรกะที่กรองการเข้าร่วม

ข้อความค้นหาไม่ถูกต้อง

หนึ่งที่มีการเรียงลำดับจะถูกขับเคลื่อนโดยตัวเลือก (ใหม่) 3 ที่แต่ละกลุ่มทั้งสอง (29 และ 31) มี ตัวเลือก 3 ทำการจัดเรียงแบบฟิสิคัลบนผลลัพธ์ของการสแกนช่วงที่กล่าวถึงก่อนหน้า (ตัวเลือก 1 ของแต่ละกลุ่ม)

ทำไม?

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

ฉันสามารถสรุปได้ว่า:

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

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


1
ฉันเชื่อว่าความคิดเห็นของคุณเกี่ยวกับพื้นที่การค้นหาเป็นจริงที่นี่ เพื่อที่จะใช้เพียงดัชนีเครื่องมือเพิ่มประสิทธิภาพต้องยืนยันว่าเพียงพอสำหรับเงื่อนไขผ่านมา 5 ปุ่มมีความเป็นไปได้มากเกินไปที่จะตรวจสอบก่อนที่มันจะถอยกลับ ฉันอยากรู้อยากเห็นถ้าชุดคำสั่งทั้งหมดของแบบสอบถามถูกแจกแจงว่าเครื่องมือเพิ่มประสิทธิภาพจะประสบความสำเร็จกับ vs ถอยกลับได้อย่างไร
Mr.Mindor

และใช่ความไม่สอดคล้องกันดูเหมือนจะเป็นรถเล็ก ๆ น้อย ๆ แต่ก็อาจขึ้นอยู่กับอัลกอริทึมที่ใช้ในการตรวจสอบดัชนีทั้งหมดเพียงพอ หากชุดค่าผสมทั้งหมดได้รับการทดสอบคุณอาจจะสามารถเห็นรูปแบบในผลลัพธ์และกำหนดว่าจะใช้อัลกอริทึมใด ฉันคิดว่ามันถูกเขียนขึ้นเพื่อให้ทำงานได้อย่างเหมาะสมที่สุดสำหรับกรณีการใช้งานทั่วไป อาจมีทางเลือกอื่นที่สามารถค้นหาโซลูชัน 8 คีย์ได้อย่างน่าเชื่อถือภายในระยะเวลา แต่จะช้ากว่าโซลูชันปัจจุบันเมื่อมีเวลาน้อยกว่า 3-4 คีย์
Mr.Mindor
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.