INNER JOIN เทียบกับประสิทธิภาพ LEFT JOIN ใน SQL Server


259

ฉันได้สร้างคำสั่ง SQL ที่ใช้ INNER JOIN ใน 9 ตารางแล้วคำสั่งนี้ใช้เวลานานมาก (มากกว่าห้านาที) ดังนั้นชาวบ้านของฉันแนะนำให้ฉันเปลี่ยน INNER JOIN เป็น LEFT JOIN เพราะการแสดงของ LEFT JOIN ดีกว่าแม้ว่าฉันจะรู้ หลังจากที่ฉันเปลี่ยนความเร็วของการสืบค้นก็เพิ่มขึ้นอย่างมาก

ฉันอยากรู้ว่าทำไม LEFT JOIN ถึงเร็วกว่า ININ JOIN

คำสั่ง SQL ของฉันมีลักษณะดังนี้: SELECT * FROM A INNER JOIN B ON ... INNER JOIN C ON ... INNER JOIN Dเป็นต้น

อัปเดต: นี่เป็นบทสรุปของสคีมาของฉัน

FROM sidisaleshdrmly a -- NOT HAVE PK AND FK
    INNER JOIN sidisalesdetmly b -- THIS TABLE ALSO HAVE NO PK AND FK
        ON a.CompanyCd = b.CompanyCd 
           AND a.SPRNo = b.SPRNo 
           AND a.SuffixNo = b.SuffixNo 
           AND a.dnno = b.dnno
    INNER JOIN exFSlipDet h -- PK = CompanyCd, FSlipNo, FSlipSuffix, FSlipLine
        ON a.CompanyCd = h.CompanyCd
           AND a.sprno = h.AcctSPRNo
    INNER JOIN exFSlipHdr c -- PK = CompanyCd, FSlipNo, FSlipSuffix
        ON c.CompanyCd = h.CompanyCd
           AND c.FSlipNo = h.FSlipNo 
           AND c.FSlipSuffix = h.FSlipSuffix 
    INNER JOIN coMappingExpParty d -- NO PK AND FK
        ON c.CompanyCd = d.CompanyCd
           AND c.CountryCd = d.CountryCd 
    INNER JOIN coProduct e -- PK = CompanyCd, ProductSalesCd
        ON b.CompanyCd = e.CompanyCd
           AND b.ProductSalesCd = e.ProductSalesCd 
    LEFT JOIN coUOM i -- PK = UOMId
        ON h.UOMId = i.UOMId 
    INNER JOIN coProductOldInformation j -- PK = CompanyCd, BFStatus, SpecCd
        ON a.CompanyCd = j.CompanyCd
            AND b.BFStatus = j.BFStatus
            AND b.ProductSalesCd = j.ProductSalesCd
    INNER JOIN coProductGroup1 g1 -- PK = CompanyCd, ProductCategoryCd, UsedDepartment, ProductGroup1Cd
        ON e.ProductGroup1Cd  = g1.ProductGroup1Cd
    INNER JOIN coProductGroup2 g2 -- PK = CompanyCd, ProductCategoryCd, UsedDepartment, ProductGroup2Cd
        ON e.ProductGroup1Cd  = g2.ProductGroup1Cd

1
คุณฉายคุณลักษณะใด ๆ จากcoUOM? ถ้าไม่ใช่คุณอาจใช้การรวมกึ่งได้ ถ้าใช่คุณจะสามารถใช้UNIONเป็นทางเลือก การโพสต์เพียงFROMข้อของคุณคือข้อมูลไม่เพียงพอที่นี่
oneday

1
ฉันสงสัยสิ่งนี้บ่อยครั้ง (เพราะฉันเห็นตลอดเวลา)
พอลเดรเปอร์

1
คุณพลาดคำสั่งซื้อในสคีมาสั้น ๆ ของคุณหรือไม่? ฉันเพิ่งประสบปัญหาเมื่อเปลี่ยน INNER JOIN เป็น LEFT OUTER JOIN เร็วขึ้นจาก 3 นาทีเป็น 10 วินาที หากคุณมี Order By ในแบบสอบถามของคุณฉันจะอธิบายเพิ่มเติมในภายหลัง ดูเหมือนว่าคำตอบทั้งหมดไม่ได้อธิบายกรณีที่ฉันเผชิญ
Phuah Yee Keat

คำตอบ:


403

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

(และแม้ว่า a LEFT JOIN จะเร็วกว่าในสถานการณ์ที่เฉพาะเจาะจงเนื่องจากการรวมกันของปัจจัยที่ยากต่อการจินตนาการบางอย่างมันไม่ได้เทียบเท่ากับฟังก์ชันINNER JOINดังนั้นคุณจึงไม่สามารถไปแทนที่อินสแตนซ์ทั้งหมดของอันอื่นด้วย!

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


แก้ไข:

เมื่อพิจารณาเพิ่มเติมเกี่ยวกับเรื่องนี้ฉันสามารถคิดถึงสถานการณ์หนึ่งสถานการณ์ที่LEFT JOINอาจเร็วกว่าINNER JOINและนั่นก็คือเมื่อ:

  • บางตารางมีขนาดเล็กมาก (พูดน้อยกว่า 10 แถว)
  • ตารางไม่มีดัชนีเพียงพอที่จะครอบคลุมแบบสอบถาม

ลองพิจารณาตัวอย่างนี้:

CREATE TABLE #Test1
(
    ID int NOT NULL PRIMARY KEY,
    Name varchar(50) NOT NULL
)
INSERT #Test1 (ID, Name) VALUES (1, 'One')
INSERT #Test1 (ID, Name) VALUES (2, 'Two')
INSERT #Test1 (ID, Name) VALUES (3, 'Three')
INSERT #Test1 (ID, Name) VALUES (4, 'Four')
INSERT #Test1 (ID, Name) VALUES (5, 'Five')

CREATE TABLE #Test2
(
    ID int NOT NULL PRIMARY KEY,
    Name varchar(50) NOT NULL
)
INSERT #Test2 (ID, Name) VALUES (1, 'One')
INSERT #Test2 (ID, Name) VALUES (2, 'Two')
INSERT #Test2 (ID, Name) VALUES (3, 'Three')
INSERT #Test2 (ID, Name) VALUES (4, 'Four')
INSERT #Test2 (ID, Name) VALUES (5, 'Five')

SELECT *
FROM #Test1 t1
INNER JOIN #Test2 t2
ON t2.Name = t1.Name

SELECT *
FROM #Test1 t1
LEFT JOIN #Test2 t2
ON t2.Name = t1.Name

DROP TABLE #Test1
DROP TABLE #Test2

หากคุณเรียกใช้และดูแผนการดำเนินการคุณจะเห็นว่าINNER JOINข้อความค้นหานั้นมีราคาสูงกว่าLEFT JOINเพราะเป็นไปตามเกณฑ์สองข้อด้านบน เป็นเพราะ SQL Server ต้องการทำการแฮชที่ตรงกันสำหรับINNER JOIN, แต่ซ้อนกันวนซ้ำสำหรับLEFT JOIN; อดีตเป็นปกติได้เร็วขึ้นมาก แต่เนื่องจากจำนวนแถวที่มีขนาดเล็กเพื่อให้และมีดัชนีการใช้งานไม่มีการดำเนินการคร่ำเครียดจะออกมาเป็นส่วนที่แพงที่สุดของแบบสอบถาม

คุณสามารถเห็นเอฟเฟกต์เดียวกันโดยการเขียนโปรแกรมในภาษาการเขียนโปรแกรมที่คุณชื่นชอบเพื่อทำการค้นหาจำนวนมากในรายการที่มี 5 องค์ประกอบเทียบกับตารางแฮชที่มี 5 องค์ประกอบ เนื่องจากขนาดเวอร์ชันของตารางแฮชจึงช้ากว่าจริง แต่เพิ่มเป็น 50 อิลิเมนต์หรือ 5,000 อิลิเมนต์และเวอร์ชันลิสต์จะช้ากว่าการรวบรวมข้อมูลเนื่องจากเป็น O (N) กับ O (1) สำหรับ hashtable

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

ดังนั้นข้อสรุปคือสิ่งที่ฉันพูดถึงหลายย่อหน้าข้างต้นมากหรือน้อย นี่เป็นปัญหาการจัดทำดัชนีหรือดัชนีการครอบคลุมอย่างแน่นอนซึ่งอาจรวมกับตารางขนาดเล็กหนึ่งตารางหรือมากกว่า เหล่านี้เป็นสถานการณ์เฉพาะภายใต้ซึ่ง SQL Server อาจบางครั้งเลือกแผนการดำเนินการที่เลวร้ายยิ่งสำหรับกว่าINNER JOINLEFT JOIN


4
มีอีกสถานการณ์หนึ่งที่สามารถนำไปสู่การเข้าร่วมนอกทำงานได้ดีกว่าการเข้าร่วมภายใน ดูคำตอบของฉันด้านล่าง
dbenham

12
ฉันต้องการชี้ให้เห็นว่าโดยทั่วไปไม่มีเอกสารฐานข้อมูลเพื่อสนับสนุนแนวคิดที่ว่าการรวมภายในและภายนอกเข้าร่วมการทำงานแตกต่างกัน การรวมภายนอกจะมีราคาแพงกว่าการรวมภายในเล็กน้อยเนื่องจากปริมาณข้อมูลและขนาดของชุดผลลัพธ์ อย่างไรก็ตามอัลกอริทึมพื้นฐาน ( msdn.microsoft.com/en-us/library/ms191426(v=sql.105).aspx ) จะเหมือนกันสำหรับการรวมทั้งสองประเภท ประสิทธิภาพควรจะคล้ายกันเมื่อพวกเขาส่งคืนข้อมูลจำนวนเท่ากัน
Gordon Linoff

3
@Aaronaught . . คำตอบนี้ถูกอ้างถึงในความคิดเห็นที่พูดอะไรบางอย่างกับผลกระทบที่ ฉันแสดงความคิดเห็นเพียงเพื่อให้แน่ใจว่าการตีความผิดนี้ไม่ได้แพร่กระจาย
Gordon Linoff

16
ฉันคิดว่าคำตอบนี้ทำให้เข้าใจผิดในแง่มุมสำคัญอย่างหนึ่ง: เนื่องจากระบุว่า "การเข้าร่วมด้านซ้ายนั้นไม่เร็วกว่าการเข้าร่วมภายใน" อย่างแน่นอน บรรทัดนี้ไม่ถูกต้อง ในทางทฤษฎีแล้วมันไม่เร็วกว่า ININ JOIN มันเป็นไม่ได้ "อย่างไม่เร็วขึ้น". คำถามนี้เป็นคำถามเกี่ยวกับประสิทธิภาพโดยเฉพาะ ในทางปฏิบัติตอนนี้ฉันได้เห็นระบบไม่กี่แห่ง (โดย บริษัท ขนาดใหญ่มาก!) ซึ่ง INNER JOIN นั้นช้ามากเมื่อเปรียบเทียบกับ OINTER JOIN ทฤษฎีและการปฏิบัติเป็นสิ่งที่แตกต่างกันมาก
David Frenkel

5
@DavidFrenkel: นั่นไม่น่าเป็นไปได้สูง ฉันขอดูการเปรียบเทียบ A / B พร้อมกับแผนการดำเนินการหากคุณเชื่อว่าเป็นไปได้ อาจเกี่ยวข้องกับแผนแบบสอบถาม / การดำเนินการแคชหรือสถิติไม่ดี
Aaronaught

127

มีสถานการณ์สำคัญหนึ่งอย่างที่สามารถนำไปสู่การรวมภายนอกได้เร็วกว่าการรวมภายในที่ยังไม่ได้กล่าวถึง

เมื่อใช้การรวมภายนอกเครื่องมือเพิ่มประสิทธิภาพจะปล่อยตารางการรวมภายนอกจากแผนการดำเนินการเสมอหากคอลัมน์การรวมเป็น PK ของตารางภายนอกและไม่มีการอ้างอิงคอลัมน์ภายนอกตารางภายนอกนอกการรวมภายนอกเอง ตัวอย่างSELECT A.* FROM A LEFT OUTER JOIN B ON A.KEY=B.KEYและ B.KEY คือ PK สำหรับ B. ทั้ง Oracle (ฉันเชื่อว่าฉันใช้รีลีส 10) และ Sql Server (ฉันใช้ 2008 R2) พรุนตาราง B จากแผนการดำเนินการ

สิ่งเดียวกันไม่จำเป็นต้องเป็นจริงสำหรับการเข้าร่วมภายใน: SELECT A.* FROM A INNER JOIN B ON A.KEY=B.KEYอาจหรือไม่จำเป็นต้องใช้ B ในแผนการดำเนินการทั้งนี้ขึ้นอยู่กับข้อ จำกัด ที่มีอยู่

ถ้า A.KEY เป็น foreign key ที่ไม่มีค่าที่อ้างอิงถึง B.KEY ตัวเพิ่มประสิทธิภาพจะไม่สามารถวาง B จากแผนได้เพราะต้องยืนยันว่าแถว B นั้นมีอยู่สำหรับทุกแถว A

ถ้า A.KEY เป็นคีย์ foreign foreign บังคับให้อ้างอิง B.KEY ดังนั้นเครื่องมือเพิ่มประสิทธิภาพสามารถปล่อย B จากแผนได้เนื่องจากข้อ จำกัด รับประกันการมีอยู่ของแถว แต่เพียงเพราะเครื่องมือเพิ่มประสิทธิภาพสามารถวางตารางจากแผนไม่ได้หมายความว่ามันจะ SQL Server 2008 R2 ไม่ปล่อย B จากแผน Oracle 10 DOES วาง B จากแผน มันง่ายที่จะดูว่าการรวมภายนอกจะดำเนินการรวมภายในบน SQL Server ในกรณีนี้ได้อย่างไร

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

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

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

หมายเหตุสุดท้ายหนึ่ง - ฉันยังไม่ได้ทดสอบผลกระทบต่อประสิทธิภาพการทำงานในแง่ของข้างต้น แต่ในทางทฤษฎีดูเหมือนว่าคุณควรจะสามารถแทนที่ INNER JOIN ได้อย่างปลอดภัยด้วยการเข้าร่วมภายนอกถ้าคุณเพิ่มเงื่อนไข <FOREIGN_KEY> เป็นโมฆะ ไปยังข้อที่


5
ฉันเจอปัญหานี้จริง ๆ เมื่อสร้างคิวรีแบบไดนามิกมาก ฉันทิ้งไว้ใน INNER JOIN ที่ฉันใช้และไม่ดึงข้อมูลจากและเมื่อฉันเปลี่ยนเป็น LEFT JOIN (จากความอยากรู้ที่ไม่เห็นด้วยแรงเฉือน) การสืบค้นนั้นเร็วขึ้นจริง ๆ
Erik Philips

1
แก้ไข - ชี้แจงเงื่อนไขที่ต้องมีอยู่เพื่อให้เครื่องมือเพิ่มประสิทธิภาพวางตารางการรวมภายนอกจากแผนการดำเนินการ
dbenham

2
คำอธิบายเล็กน้อยสำหรับคำตอบของคุณ: เมื่อคอลัมน์คีย์ต่างประเทศไม่สามารถลบล้างได้ INNER JOIN และ LEFT JOIN จะเทียบเท่ากันในเชิงความหมาย (เช่นคำแนะนำ WHERE ของคุณซ้ำซ้อน); ความแตกต่างเพียงอย่างเดียวคือแผนการดำเนินการ
ดักลาส

2
ถึงแม้ว่าสิ่งนี้แสดงให้เห็นถึงตัวอย่างที่น่ารำคาญจริง ๆ นี่เป็นคำตอบที่ชาญฉลาดมาก!
pbalaga

6
+1: ฉันดูเหมือนจะพบกับสิ่งนี้เมื่อมีคำถามสองสามข้อที่ฉันใช้การรวมภายในกับตารางที่มีขนาดใหญ่มาก การรวมภายในทำให้เกิดการรั่วไหลของ tempdb ในแผนคิวรี (ฉันคิดว่าด้วยเหตุผลที่กล่าวไว้ข้างต้น - และเซิร์ฟเวอร์ของฉันขาด RAM เพื่อเก็บทุกอย่างไว้ในหน่วยความจำ) การสลับไปทางซ้ายเป็นการตัดการรั่วไหลออกเป็น tempdb ทำให้ผลลัพธ์ของแบบสอบถาม 20-30 วินาทีของฉันบางส่วนทำงานเป็นเสี้ยววินาที นี่เป็น gotcha สำคัญมากที่เห็นเนื่องจากคนส่วนใหญ่ดูเหมือนจะทำให้สมมติฐานครอบคลุมว่าการรวมภายในได้เร็วขึ้น
phosplait

23

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

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

ฉันเคยประสบกับกรณีที่การเข้าร่วมด้านซ้ายเร็วกว่าการเข้าร่วมภายใน

เหตุผลพื้นฐานคือ: ถ้าคุณมีสองตารางและคุณเข้าร่วมในคอลัมน์ที่มีดัชนี (ทั้งสองตาราง) การรวมภายในจะสร้างผลลัพธ์เดียวกันไม่ว่าคุณจะวนซ้ำรายการในดัชนีในตารางที่หนึ่งและจับคู่กับดัชนีในตารางที่สองราวกับว่าคุณทำรายการย้อนกลับ: วนซ้ำรายการในดัชนีในตารางที่สองและจับคู่กับดัชนี ในตารางที่หนึ่ง ปัญหาคือเมื่อคุณมีสถิติที่ทำให้เข้าใจผิดเครื่องมือเพิ่มประสิทธิภาพการสืบค้นจะใช้สถิติของดัชนีเพื่อค้นหาตารางที่มีรายการที่ตรงกันน้อยที่สุด (ตามเกณฑ์อื่น ๆ ของคุณ) หากคุณมีสองตารางที่มี 1 ล้านในแต่ละตัวในตารางที่หนึ่งคุณมีการจับคู่ 10 แถวและในตารางที่สองคุณมีการจับคู่ 100000 แถว วิธีที่ดีที่สุดคือทำการสแกนดัชนีในตารางที่หนึ่งและจับคู่ 10 ครั้งในตารางที่สอง การย้อนกลับนั้นเป็นการสแกนดัชนีที่วนแถวมากกว่า 100,000 แถวและพยายามจับคู่ 100,000 ครั้งและสำเร็จเพียง 10 ครั้ง ดังนั้นหากสถิติไม่ถูกต้องเครื่องมือเพิ่มประสิทธิภาพอาจเลือกตารางและดัชนีที่ไม่ถูกต้องเพื่อวนซ้ำ

หากเครื่องมือเพิ่มประสิทธิภาพเลือกที่จะเพิ่มประสิทธิภาพการรวมด้านซ้ายในลำดับที่มีการเขียนไว้มันจะทำงานได้ดีกว่าการรวมภายใน

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


18

ลองใช้ข้อความค้นหาทั้งสอง (ข้อความที่มีการเข้าร่วมภายในและซ้าย) ด้วยOPTION (FORCE ORDER)ที่ท้ายและโพสต์ผลลัพธ์ OPTION (FORCE ORDER)คือคำใบ้คิวรีที่บังคับให้เครื่องมือเพิ่มประสิทธิภาพเพื่อสร้างแผนการดำเนินการโดยมีลำดับการเข้าร่วมที่คุณระบุไว้ในแบบสอบถาม

หากINNER JOINเริ่มทำงานเร็วเท่าที่เป็นLEFT JOINเพราะ:

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

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


9

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

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

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

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


8

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

กรณีที่แย่ที่สุดคุณสามารถทำการสแกนทั้ง 9 ตารางสำหรับการเข้าร่วมแต่ละครั้งได้อย่างง่ายดาย


7

การรวมภายนอกสามารถนำเสนอประสิทธิภาพที่เหนือกว่าเมื่อใช้ในมุมมอง

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

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

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

ที่มา: http://www.sqlservercentral.com/blogs/sql_coach/2010/07/29/poor-little-misunderstood-views/


1
คำสั่งของคุณเกี่ยวกับ "เข้าร่วมด้านนอก" ทำให้เข้าใจผิดและอาจไม่ถูกต้อง ด้านนอกหมายความว่าไม่จำเป็นต้องมีข้อมูลในอีกด้านหนึ่งและถ้าไม่ได้แทนที่ NULL ภายใต้สถานการณ์ที่เฉพาะเจาะจง RDBMS อาจ "ข้าม" พวกเขา (ดูคำตอบข้างต้นจาก dbenham) HOWEVER - ด้านนอก vs ด้านในอาจทำให้ข้อความค้นหาของคุณแสดงผลลัพธ์ที่แตกต่างอย่างสิ้นเชิง INNER หมายถึง - ให้ผลลัพธ์ที่รายการนั้นอยู่ในทั้ง A & B ด้านซ้ายหมายถึง A ทั้งหมดและ B ทางเลือกถ้ามันมีอยู่ กรณีแรก - คุณได้แถวบางส่วนในวินาทีคุณได้แถวทั้งหมด
ripvlan

1
@ripvlan แน่นอนการรวมภายนอกและภายในไม่สามารถเปลี่ยนได้เสมอ คำถามเดิมคือเกี่ยวกับประสิทธิภาพซึ่งหมายความว่าเรากำลังพูดถึงกรณีที่ทั้งเข้าร่วมจะกลับชุดผลลัพธ์เดียวกัน
MarredCheese

1
ใช่และ - OUTER อาจทำให้เกิดปัญหาประสิทธิภาพเนื่องจากจะทำให้แถวทั้งหมด (ข้อมูลเพิ่มเติม) ถูกส่งคืน ข้อสันนิษฐานของคุณว่าแบบสอบถามส่งผลให้ผลลัพธ์เดียวกันนั้นเป็นสิ่งที่ยุติธรรม - อย่างไรก็ตามมันไม่เป็นความจริงในกรณีทั่วไปและเฉพาะสำหรับการออกแบบฐานข้อมูลแต่ละรายการ และสำหรับผู้ที่ไม่คุ้นเคย 100% กับพีชคณิตเชิงสัมพันธ์อาจทำให้พวกเขาเศร้าโศก ประเด็นของฉันคือเพื่อให้ข้อมูลเชิงลึกแก่ผู้อ่านที่กำลังมองหาคำแนะนำมากขึ้นและด้านซ้าย / ขวาไม่สามารถแก้ปัญหาได้อย่างน่าอัศจรรย์และอาจทำให้เกิดปัญหามากขึ้น เป็นพลังที่เหลือสำหรับเลเวล 300 :-)
ripvlan

2

ฉันพบสิ่งที่น่าสนใจในเซิร์ฟเวอร์ SQL เมื่อตรวจสอบว่าการรวมภายในเร็วกว่าการรวมซ้าย

หากคุณไม่รวมรายการของตารางการเข้าร่วมด้านซ้ายในคำสั่งเลือกการรวมทางซ้ายจะเร็วกว่าการสืบค้นเดียวกันที่มีการรวมภายใน

หากคุณรวมตารางด้านซ้ายเข้าร่วมในคำสั่งเลือกการรวมภายในด้วยแบบสอบถามเดียวกันเท่ากับหรือเร็วกว่าการรวมซ้าย


0

จากการเปรียบเทียบของฉันฉันพบว่าพวกเขามีแผนการดำเนินการที่แน่นอน มีสามสถานการณ์:

  1. หากและเมื่อพวกเขากลับผลลัพธ์เดียวกันพวกเขาก็มีความเร็วเท่ากัน อย่างไรก็ตามเราต้องจำไว้ว่าคำค้นหานั้นไม่เหมือนกันและอาจเข้าร่วมด้านซ้ายอาจส่งคืนผลลัพธ์เพิ่มเติม (เมื่อไม่ตรงกับเงื่อนไข ON) - นี่คือสาเหตุที่มักจะช้ากว่า

  2. เมื่อตารางหลัก (ไม่ใช่ non-const แรกในแผนการดำเนินการ) มีเงื่อนไขที่ จำกัด (WHERE id =?) และเงื่อนไข ON ที่สอดคล้องกันอยู่บนค่า NULL ตาราง "right" จะไม่เข้าร่วม --- นี่คือเมื่อ ซ้ายเข้าร่วมเร็วขึ้น

  3. ดังที่กล่าวไว้ในจุดที่ 1 โดยปกติแล้วผู้เข้าร่วมจะมีข้อ จำกัด มากกว่าและให้ผลลัพธ์ที่น้อยลงและเร็วขึ้น

ทั้งสองใช้ (เดียวกัน) ดัชนี

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