มีความแตกต่างในการดำเนินการระหว่างเงื่อนไข JOIN และเงื่อนไข WHERE หรือไม่


17

มีความแตกต่างของประสิทธิภาพระหว่างเคียวรีตัวอย่างทั้งสองหรือไม่

แบบสอบถาม 1:

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
where  b.tag = 'Y'

แบบสอบถาม 2;

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
   and b.tag = 'Y'

สังเกตเห็นความแตกต่างเพียงอย่างเดียวคือการวางเงื่อนไขเสริม; ครั้งแรกที่ใช้WHEREประโยคและครั้งที่สองจะเพิ่มเงื่อนไขในONข้อ

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

มีกฎทั่วไปที่ต้องปฏิบัติตามเมื่อมีการเข้ารหัสคิวรีเช่นนี้ ฉันเดาว่ามันต้องขึ้นอยู่กับแพลตฟอร์มเพราะเห็นได้ชัดว่ามันไม่ได้สร้างความแตกต่างให้กับฐานข้อมูลของฉัน แต่บางทีนั่นอาจเป็นเพียงคุณสมบัติของ Teradata และถ้ามันเป็นขึ้นอยู่กับแพลตฟอร์มผมชอบมากที่จะได้รับการอ้างอิงเอกสารไม่กี่; ฉันไม่รู้ว่าจะมองหาอะไรจริงๆ


9
มันขึ้นอยู่กับแพลตฟอร์มเนื่องจากมันขึ้นอยู่กับวิธีที่เครื่องมือเพิ่มประสิทธิภาพ RDBMS จัดการกับการแยกวิเคราะห์และการเพิ่มประสิทธิภาพ
Philᵀᴹ

8
และคำตอบในคำถามที่เชื่อมโยงนั้นสมควรได้รับ downvotes หลายอัน แม้แต่เครื่องมือเพิ่มประสิทธิภาพดั้งเดิมของ MySQL ก็เข้าใจว่าแบบสอบถามแบบง่าย ๆ เหล่านี้มีค่าเท่ากันและ"ประโยค WHERE ถูกประเมินหลังจากทำการรวมทั้งหมดแล้ว"เป็นจริงเฉพาะในระดับตรรกะไม่ใช่ในการดำเนินการจริง
ypercubeᵀᴹ

1
ไม่ซ้ำกันจริงๆ คำถามนั้นและคำตอบคือการเปรียบเทียบไวยากรณ์เข้าร่วม "โดยนัย" กับ "ชัดเจน" ฉันถามเฉพาะเกี่ยวกับเงื่อนไขการเข้าร่วมเพิ่มเติม
BellevueBob

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

คำตอบ:


14

อ้างอิงจากบทที่ 9 (Parser และเครื่องมือเพิ่มประสิทธิภาพ) หน้า 172 ของหนังสือเข้าใจ MySQL ภายในโดย Sasha Pachev

ทำความเข้าใจกับ MySQL Internals

นี่คือการสลายการประเมินผลของแบบสอบถามเป็นงานต่อไปนี้:

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

ในหน้าเดียวกันนั้นจะกล่าวสิ่งต่อไปนี้:

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

บทส่งท้าย

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

ฉันเขียนเกี่ยวกับการเล่นโวหารนี้ก่อน

เพราะเครื่องมือเพิ่มประสิทธิภาพการสืบค้น MySQL สามารถทำการยกเลิกคีย์บางอย่างในระหว่างการประเมินผลของแบบสอบถาม

ความคิดเห็นของ @ Phil ช่วยให้ฉันเห็นวิธีโพสต์คำตอบนี้ (+1 สำหรับความคิดเห็นของ @ Phil)

ความคิดเห็นของ @ ypercube (+1 สำหรับสิ่งนี้ด้วย) เป็นรุ่นที่กะทัดรัดของโพสต์ของฉันเพราะ MySQL Query Optimizer เป็นพื้นฐาน น่าเสียดายที่มันต้องเกี่ยวข้องกับเอ็นจิ้นการเก็บข้อมูลภายนอก

สรุปผลการศึกษา

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

  • การนับแถว
  • การเลือกปุ่ม
  • ชุดผลลัพธ์การนวดเป็นระยะ
  • โอ้ใช่เข้าร่วมจริง

คุณอาจจะต้องบีบบังคับลำดับของการดำเนินการโดยการเขียนใหม่ (refactoring) แบบสอบถาม

นี่คือคิวรีแรกที่คุณให้

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
where  b.tag = 'Y';

ลองเขียนใหม่เพื่อประเมิน WHERE ก่อน

select count(*)
from   table1 a
join   (select key_col from table2 where tag='Y') b
on     b.key_col=a.key_col;

นั่นจะเปลี่ยนแผนอย่างชัดเจน มันสามารถสร้างผลลัพธ์ที่ดีขึ้นหรือแย่ลง

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

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


2
+1 สำหรับข้อมูลเฉพาะ MySQL อย่างละเอียดและโดยเฉพาะอย่างยิ่งเพื่อหลอกให้ฉันเรียนรู้ความแตกต่างระหว่าง "Epilogue" และ "สรุป"!
BellevueBob

ในโพสต์ของฉันบทส่งท้ายเป็นบทสรุป
RolandoMySQLDBA

6
@Rolando: คุณสามารถเพิ่มAftermathเกี่ยวกับการปรับปรุงตัวเพิ่มประสิทธิภาพในรุ่น MariaDB (5.3 และ 5.5) ล่าสุดและในเวอร์ชันหลัก MySQL (5.6) ที่เพิ่งเปิดตัว ซึ่งอาจทำให้การเขียนใหม่ไม่มีความจำเป็น
ypercubeᵀᴹ

1

สำหรับ Oracle เนื่องจาก mySQL มีคำอธิบายที่ยาวเราจึงมีวิธีการใช้ประโยชน์จากเครื่องมือเพิ่มประสิทธิภาพในระดับสูง 2 วิธี

อันดับแรกคือการเพิ่มประสิทธิภาพตามกฎ (หรือ RBO) Oracle มีกฎที่กำหนดไว้ 15 ข้อซึ่งแต่ละแบบสอบถามจะแยกวิเคราะห์ความพยายามที่จะปฏิบัติตามลำดับที่กำหนดไว้ หากไม่สามารถสร้างคิวรีที่ปรับให้เหมาะสมจากกฎ 1 มันจะย้ายไปยังกฎ 2 และเป็นต้นไปจนกว่าจะถึงกฎ 15

สำหรับข้อมูลเพิ่มเติม: https://docs.oracle.com/cd/B10500_01/server.920/a96533/rbo.htm

สิ่งเหล่านี้ส่งผลต่อเมล็ด Oracle RDBMS ตั้งแต่ 11.1 และต่ำกว่าที่ไม่ได้ถูกแปลงเป็นเครื่องมือเพิ่มประสิทธิภาพต้นทุน (aka CBO) Oracle 11.2 หรือสูงกว่านั้นต้องการเครื่องมือเพิ่มประสิทธิภาพ CBO แต่สามารถบังคับใช้รหัส SQL เฉพาะเพื่อปรับให้เหมาะสมในวิธีการ RBO แบบเก่าหากผู้ใช้ต้องการ

CBO สำหรับ Oracle 11.1+ จะทำการวางแผนการดำเนินการหลายอย่างสำหรับ SQL ID เดียวกันและดำเนินการหนึ่งด้วยค่าใช้จ่ายที่คาดหวังโดยรวมน้อยที่สุด มันใช้ประโยชน์จากตรรกะจำนวนมากจาก RBO แต่วิเคราะห์สถิติตารางเพื่อสร้างต้นทุนแผนปฏิบัติการแบบไดนามิกสำหรับการดำเนินการแต่ละครั้งที่ฐานข้อมูลต้องทำเพื่อให้ข้อมูลแก่ผู้ใช้ปลายทาง การดำเนินการสแกนเต็มตารางในตารางที่มีขนาดใหญ่มากนั้นมีค่าใช้จ่ายสูงมาก ดำเนินการสแกนตารางเต็มรูปแบบบนตารางที่มี 10 แถวราคาถูก ใน RBO เหล่านี้ถือเป็นการดำเนินงานที่เท่าเทียมกัน

สำหรับข้อมูลเพิ่มเติม: https://oracle-base.com/articles/misc/cost-based-optimizer-and-database-statistics

สำหรับตัวอย่างการสืบค้นเฉพาะของคุณ: ออราเคิลมีแนวโน้มที่จะวิเคราะห์ข้อมูลเพื่อให้แผนการดำเนินการที่แตกต่างกันและหนึ่งจะดีกว่าในทางเทคนิคอื่น ๆ อย่างไรก็ตามสิ่งนี้อาจแตกต่างกันเล็กน้อย การทำให้ตาดูทั้ง Oracle RBO และ CBO ต้องการการสืบค้น 1 มากขึ้นเนื่องจากกำลังรันการเข้าร่วมโดยมีเงื่อนไขน้อยกว่าและจากนั้นกรองคอลัมน์เฉพาะจากตารางชั่วคราวที่ทำจากการเข้าร่วม


1

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

  1. แบบสอบถามทั้งสองมีแผนการดำเนินการเดียวกัน นั่นเป็นเรื่องปกติและเป็นสิ่งที่เราคาดหวัง หวังว่าจะเป็นแผนการดำเนินการที่ดีที่สุดสำหรับแบบสอบถาม
  2. มีแผนการดำเนินการที่แตกต่างกัน เรามีสองหน่วยย่อยที่นี่

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

    2.2 แบบสอบถามมีแผนการดำเนินการที่แตกต่างกันและแผนหนึ่งดีกว่าอีกแผน เรามี subcase อีกครั้ง:

    2.2.1 แผนแตกต่างกันเนื่องจากแบบสอบถามไม่เท่ากัน ดังนั้นตรวจสอบอย่างรอบคอบว่าพวกเขาเทียบเท่าจริง ๆ ในกรณีของคุณพวกเขาเทียบเท่ากันจริงๆ

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

    2.2.3 แผนการแตกต่างกันแบบสอบถามมีความเท่าเทียมกันซอฟต์แวร์ฐานข้อมูลมีข้อบกพร่อง

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