เข้าร่วมด้วยตนเองในคีย์หลัก


9

พิจารณาคำถามนี้ซึ่งประกอบด้วยการรวมNตัวเอง:

select
    t1.*
from [Table] as t1
join [Table] as t2 on
    t1.Id = t2.Id
-- ...
join [Table] as tN on
    t1.Id = tN.Id

มันสร้างแผนการดำเนินการด้วยการสแกนดัชนี N คลัสเตอร์และการรวม N-1 ผสาน

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

select
    t1.*
from [Table] as t1

คำถาม

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

ทดสอบเมื่อ:

  • เซิร์ฟเวอร์ต้นทางรุ่น: SQL Server 2014 (12.0.4213)
  • Source Database Engine Edition: Microsoft SQL Server Standard Edition
  • ประเภทโปรแกรมฐานข้อมูลต้นทาง: เซิร์ฟเวอร์ SQL แบบสแตนด์อโลน
  • ระดับความเข้ากันได้: SQL Server 2008 (100)

แบบสอบถามไม่มีความหมาย มันมาถึงใจของฉันและฉันอยากรู้เกี่ยวกับมันตอนนี้

นี่คือซอกับการสร้างตารางและ 3 คำสั่ง: กับinner join's, กับleft join' s และผสม คุณยังสามารถดูแผนการดำเนินการที่นั่นได้เช่นกัน

ดูเหมือนว่าleft joins จะถูกตัดออกในแผนการดำเนินการผลลัพธ์ขณะที่inner joins ไม่ได้เป็น ยังคงไม่ได้รับเหตุผลที่แม้ว่า

คำตอบ:


18

ก่อนอื่นให้ถือว่านั่น(id)คือคีย์หลักของตาราง ในกรณีนี้ใช่การรวมกัน (สามารถพิสูจน์ได้) ซ้ำซ้อนและสามารถกำจัดได้

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

โดยส่วนตัวมันฟังดูไม่เหมือน (ธรรมดาพอ) แบบสอบถาม - ตามที่คุณยอมรับ - ดูค่อนข้างงี่เง่าและผู้ตรวจทานไม่ควรปล่อยให้ผ่านการตรวจสอบเว้นแต่จะได้รับการปรับปรุงและลบการเข้าร่วมซ้ำซ้อน

ที่กล่าวว่ามีคำถามที่คล้ายกันซึ่งการกำจัดจะเกิดขึ้น มีโพสต์บล็อกที่ดีมากที่เกี่ยวข้องโดย Rob ลี่ย์คือJOIN ความเรียบง่ายใน SQL Server

ในกรณีของเราสิ่งที่เราต้องทำในการเปลี่ยนการรวมเป็นการLEFTรวม ดูdbfiddle.uk เครื่องมือเพิ่มประสิทธิภาพในกรณีนี้รู้ว่าสามารถลบการเข้าร่วมได้อย่างปลอดภัยโดยไม่ต้องเปลี่ยนผลลัพธ์ (ตรรกะการทำให้เข้าใจง่ายเป็นเรื่องทั่วไปและไม่ได้เป็นกรณีพิเศษสำหรับการรวมตัวเอง)

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

ALTER TABLE "Table"
    ADD FOREIGN KEY (id) REFERENCES "Table" (id) ;

และ voila การรวมจะถูกกำจัด! (ทดสอบในซอเดียวกัน): ที่นี่

create table docs
(id int identity primary key,
 doc varchar(64)
) ;
GO
insert
into docs (doc)
values ('Enter one batch per field, don''t use ''GO''')
     , ('Fields grow as you type')
     , ('Use the [+] buttons to add more')
     , ('See examples below for advanced usage')
  ;
GO
ได้รับผลกระทบ 4 แถว
--------------------------------------------------------------------------------
-- Or use XML to see the visual representation, thanks to Justin Pealing and
-- his library: https://github.com/JustinPealing/html-query-plan
--------------------------------------------------------------------------------
set statistics xml on;
select d1.* from docs d1 
    join docs d2 on d2.id=d1.id
    join docs d3 on d3.id=d1.id
    join docs d4 on d4.id=d1.id;
set statistics xml off;
GO
id | คุณหมอ                                      
-: | : ----------------------------------------
 1 | ป้อนหนึ่งชุดต่อฟิลด์อย่าใช้ 'GO'
 2 | เขตข้อมูลเติบโตในขณะที่คุณพิมพ์                  
 3 | ใช้ปุ่ม [+] เพื่อเพิ่มมากขึ้น          
 4 | ดูตัวอย่างด้านล่างสำหรับการใช้งานขั้นสูง    

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

--------------------------------------------------------------------------------
-- Or use XML to see the visual representation, thanks to Justin Pealing and
-- his library: https://github.com/JustinPealing/html-query-plan
--------------------------------------------------------------------------------
set statistics xml on;
select d1.* from docs d1 
    left join docs d2 on d2.id=d1.id
    left join docs d3 on d3.id=d1.id
    left join docs d4 on d4.id=d1.id;
set statistics xml off;
GO
id | คุณหมอ                                      
-: | : ----------------------------------------
 1 | ป้อนหนึ่งชุดต่อฟิลด์อย่าใช้ 'GO'
 2 | เขตข้อมูลเติบโตในขณะที่คุณพิมพ์                  
 3 | ใช้ปุ่ม [+] เพื่อเพิ่มมากขึ้น          
 4 | ดูตัวอย่างด้านล่างสำหรับการใช้งานขั้นสูง    

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

alter table docs
  add foreign key (id) references docs (id) ;
GO
--------------------------------------------------------------------------------
-- Or use XML to see the visual representation, thanks to Justin Pealing and
-- his library: https://github.com/JustinPealing/html-query-plan
--------------------------------------------------------------------------------
set statistics xml on;
select d1.* from docs d1 
    join docs d2 on d2.id=d1.id
    join docs d3 on d3.id=d1.id
    join docs d4 on d4.id=d1.id;
set statistics xml off;
GO
id | คุณหมอ                                      
-: | : ----------------------------------------
 1 | ป้อนหนึ่งชุดต่อฟิลด์อย่าใช้ 'GO'
 2 | เขตข้อมูลเติบโตในขณะที่คุณพิมพ์                  
 3 | ใช้ปุ่ม [+] เพื่อเพิ่มมากขึ้น          
 4 | ดูตัวอย่างด้านล่างสำหรับการใช้งานขั้นสูง    

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


2

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

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


1

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

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

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