เข้าร่วมแบบสอบถามเปรียบเทียบกับแบบสอบถามหลายรายการ


181

การสืบค้นเข้าร่วมจะเร็วกว่าการสืบค้นหลายครั้งหรือไม่ (คุณเรียกใช้คิวรีหลักของคุณและจากนั้นคุณเรียกใช้ SELECT อื่น ๆ มากมายขึ้นอยู่กับผลลัพธ์จากแบบสอบถามหลักของคุณ)

ฉันถามเพราะการเข้าร่วมจะทำให้การออกแบบแอปพลิเคชันของฉันซับซ้อนขึ้นมาก

หากพวกเขาเร็วขึ้นใคร ๆ จะประมาณคร่าวๆได้ไหม? ถ้า 1.5x ฉันไม่สนใจ แต่ถ้าเป็น 10x ฉันคิดว่าฉันทำ


ฉันคิดว่าพวกเขาจะเร็วขึ้น ฉันรู้ว่า INSERT หนึ่งรายการเปรียบเทียบกับคำค้นหา INSERT 10 คำค้นหานั้นเร็วกว่ามาก
alex

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

คำตอบ:


83

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


2
หากคุณเข้าร่วม 3 หรือมากกว่าตารางในคีย์ที่แตกต่างกันบ่อยครั้งที่ฐานข้อมูล (เช่น mysql) สามารถใช้ดัชนีเดียวต่อตารางซึ่งหมายความว่าหนึ่งในการรวมจะเร็ว (และใช้ดัชนี) ในขณะที่คนอื่นจะช้ามาก สำหรับหลายแบบสอบถามคุณสามารถปรับดัชนีให้เหมาะสมสำหรับแต่ละแบบสอบถาม
user151975

4
ฉันคิดว่าสิ่งนี้ขึ้นอยู่กับคำจำกัดความของคุณของ "เร็วขึ้น" ... ตัวอย่างเช่นการรวมภายใน PK 3 รายการอาจเปลี่ยนเร็วกว่าการไปกลับ 4 ครั้งเนื่องจากเครือข่ายค่าใช้จ่ายและเนื่องจากคุณต้องหยุดและเตรียมและส่งแบบสอบถามแต่ละรายการหลังจาก แบบสอบถามก่อนหน้านี้เสร็จสมบูรณ์ หากคุณต้องการสร้างมาตรฐานเซิร์ฟเวอร์ที่โหลดอย่างไรก็ตามในกรณีส่วนใหญ่การเข้าร่วมจะใช้เวลา CPU มากกว่าเมื่อเทียบกับการสืบค้น PK และมักทำให้เครือข่ายโอเวอร์เฮดเพิ่มขึ้นเช่นกัน
mindplay.dk

97

สำหรับการรวมภายในแบบสอบถามเดียวทำให้เข้าใจได้เนื่องจากคุณจะได้แถวที่ตรงกันเท่านั้น สำหรับการรวมซ้ายแบบสอบถามหลายรายการดีกว่ามาก ... ดูเกณฑ์มาตรฐานต่อไปนี้ที่ฉันทำ:

  1. แบบสอบถามเดียวที่มี 5 ตัว

    ข้อความค้นหา: 8.074508 วินาที

    ขนาดผลลัพธ์: 2268000

  2. 5 คิวรีติดต่อกัน

    เวลาสอบถามรวมกัน: 0.00262 วินาที

    ขนาดผล: 165 (6 + 50 + 7 + 12 + 90)

.

โปรดทราบว่าเราได้ผลลัพธ์เดียวกันทั้งสองกรณี (6 x 50 x 7 x 12 x 90 = 2268000)

ซ้ายเข้าร่วมใช้หน่วยความจำมากขึ้นอย่างทวีคูณด้วยข้อมูลซ้ำซ้อน

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

ตามบันทึกด้านเซิร์ฟเวอร์ MySQL ของฉันอยู่ข้างเซิร์ฟเวอร์แอปพลิเคชันของฉัน ... ดังนั้นเวลาในการเชื่อมต่อจึงน้อยมาก หากเวลาการเชื่อมต่อของคุณอยู่ในไม่กี่วินาทีก็อาจจะมีประโยชน์

ตรงไปตรงมา


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

12
@cHao พูดว่าใคร ฉันเพิ่งค้นหา SMF และ phpBB และเห็น JOINs ระหว่าง 3 ตาราง - หากคุณเพิ่มปลั๊กอินหรือแก้ไขพวกเขาสามารถเพิ่มได้อย่างง่ายดาย แอปพลิเคชันขนาดใหญ่ทุกประเภทมีศักยภาพสำหรับการเข้าร่วมจำนวนมาก เนื้อหาที่ ORM ใช้ไม่ถูกต้องเขียนผิด / ไม่สามารถเข้าร่วมตารางที่ไม่ต้องการจริง ๆ (บางทีแม้แต่ทุกตาราง)
Natalie Adams

5
@NathanAdams: การเข้าร่วมด้านซ้ายและด้านในนั้นไม่เลวเลย (อันที่จริงถ้าคุณไม่ได้เข้าร่วมตารางที่นี่และที่นั่นคุณกำลังทำผิด SQL) สิ่งที่ฉันพูดถึงคือcross joinsซึ่งมักจะเป็นที่ไม่พึงประสงค์แม้ระหว่างสองตารางให้อยู่คนเดียว 5 - และที่จะ เป็นวิธีเดียวที่จะได้ผลลัพธ์ "2268000" ที่ไม่ได้กล่าวถึงข้างต้นทั้งหมด
cHao

2
ดูผลลัพธ์ "ขนาดผล: 2268000" กับ "ขนาดผล: 165" ฉันคิดว่าการชะลอตัวของคุณกับการเข้าร่วมเป็นเพราะบันทึกของคุณมีความสัมพันธ์แบบหนึ่งต่อหลายกับคนอื่น ๆ ในขณะที่ถ้าพวกเขามีความสัมพันธ์แบบหนึ่งต่อหนึ่งการเข้าร่วมจะเร็วขึ้นมากและแน่นอนจะไม่มีผล ขนาดใหญ่กว่า SELECT
HoldOffHunger

3
@cHao เห็นได้ชัดว่าคุณยังไม่ได้พบกับวีโอไอพีในเวลาที่คุณแสดงความคิดเห็นครั้งแรก
vitoriodachef

26

คำถามนี้เก่า แต่ไม่มีการวัดประสิทธิภาพบ้าง ฉันเปรียบเทียบกับคู่แข่ง 2 รายของ JOIN:

  • ข้อความค้นหา N + 1
  • 2 เคียวรี่อันที่สองโดยใช้WHERE IN(...)หรือเทียบเท่า

ผลที่ได้คือความชัดเจน: ใน MySQL, JOINเป็นมากได้เร็วขึ้น แบบสอบถาม N + 1 สามารถลดประสิทธิภาพของแอปพลิเคชันลงอย่างมาก:

เข้าร่วมเมื่อเทียบกับที่ N + 1

นั่นคือเว้นแต่คุณจะเลือกระเบียนจำนวนมากที่ชี้ไปยังระเบียนต่างประเทศจำนวนน้อยมาก นี่คือมาตรฐานสำหรับกรณีที่รุนแรง:

เข้าร่วมกับ N + 1 - ระเบียนทั้งหมดที่ชี้ไปยังระเบียนต่างประเทศเดียวกัน

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

Takeaway:

  • สำหรับความสัมพันธ์แบบ * ต่อหนึ่งให้ใช้เสมอ JOIN
  • สำหรับความสัมพันธ์แบบ * ต่อหลายแบบสอบถามแบบที่สองอาจเร็วขึ้น

ดูบทความของฉันในสื่อสำหรับข้อมูลเพิ่มเติม


22

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

ฉันสามารถเข้าใจได้ว่าวิธีการสอบถามแบบใดแบบหนึ่งใช้เวลาพูด 0.02 วินาทีและอีกวิธีการหนึ่งใช้เวลา 20 วินาทีนั่นเป็นความแตกต่างอย่างมาก แต่ถ้าหากวิธีการสืบค้นหนึ่งวิธีใช้เวลา 0.0000000002 วินาทีและอีกวิธีหนึ่งใช้เวลา 0.0000002 วินาที ในทั้งสองกรณีวิธีหนึ่งคือมหันต์เร็วกว่าอีก 1,000 เท่า แต่จริง ๆ แล้วมันยัง "มหันต์" ในกรณีที่สองหรือไม่?

บรรทัดล่างตามที่ฉันเห็นเป็นการส่วนตัว: ถ้ามันทำงานได้ดีให้ไปหาทางออกที่ง่าย


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

@dudewad ทำให้รู้สึก ทุกอย่างขึ้นอยู่กับสิ่งที่คุณต้องการในที่สุด
Valentin Flachsel

4
ฮ่าฮ่าใช่ ... เพราะที่ google 1 nanosecond ที่หายไปนั้นมีความหมายเท่ากับสิ่งหนึ่งหมื่นล้านล้านดอลลาร์ ... แต่นั่นเป็นเพียงข่าวลือ
dudewad

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

15

ทำการทดสอบอย่างรวดเร็วโดยเลือกหนึ่งแถวจากตาราง 50,000 แถวและเข้าร่วมกับหนึ่งแถวจากตาราง 100,000 แถว โดยทั่วไปดูเหมือนว่า:

$id = mt_rand(1, 50000);
$row = $db->fetchOne("SELECT * FROM table1 WHERE id = " . $id);
$row = $db->fetchOne("SELECT * FROM table2 WHERE other_id = " . $row['other_id']);

VS

$id = mt_rand(1, 50000);
$db->fetchOne("SELECT table1.*, table2.*
    FROM table1
    LEFT JOIN table1.other_id = table2.other_id
    WHERE table1.id = " . $id);

วิธีการเลือกสองวิธีใช้เวลา 3.7 วินาทีสำหรับการอ่าน 50,000 ครั้งในขณะที่ JOIN ใช้เวลา 2.0 วินาทีในคอมพิวเตอร์ช้าที่บ้านของฉัน เข้าร่วมภายในและซ้ายเข้าร่วมไม่ได้สร้างความแตกต่าง การดึงข้อมูลหลายแถว (เช่นใช้ IN SET) ให้ผลลัพธ์ที่คล้ายกัน


1
บางทีความแตกต่างอาจเปลี่ยนเป็นอย่างอื่นหากเลือกหน้าของแถว (เช่น 20 หรือ 50) ราวกับว่าเป็นกริดสำหรับมุมมองเว็บทั่วไปและเปรียบเทียบ LEFT JOIN เดียวเข้ากับคำค้นหาสองข้อ - เลือกตัวบ่งชี้ 2 หรือ 3 ตัวกับเกณฑ์ WHERE แล้วเรียกอีกอย่าง เลือกคิวรีด้วย IN ()
JustAMartin

คอลัมน์ id และ other_id มีการจัดทำดัชนีหรือไม่?
Aarish Ramesh

11

คำถามที่แท้จริงคือ: บันทึกเหล่านี้มีความสัมพันธ์แบบหนึ่งต่อหนึ่งหรือความสัมพันธ์แบบหนึ่งต่อหลายคนหรือไม่?

คำตอบ TLDR:

หากหนึ่งต่อหนึ่งใช้JOINคำสั่ง

หากคำสั่งแบบตัวต่อตัวใช้หนึ่งSELECTคำสั่ง(หรือหลายคำสั่ง) พร้อมการปรับแต่งโค้ดฝั่งเซิร์ฟเวอร์

ทำไมและวิธีใช้ SELECT เพื่อการปรับให้เหมาะสม

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

SELECT * FROM Address WHERE Personid IN(1,2,3);

ผล:

Address.id : 1            // First person and their address
Address.Personid : 1
Address.City : "Boston"

Address.id : 2            // First person's second address
Address.Personid : 1
Address.City : "New York"

Address.id : 3            // Second person's address
Address.Personid : 2
Address.City : "Barcelona"

ที่นี่ฉันได้รับบันทึกทั้งหมดในหนึ่งคำสั่งที่เลือก นี้ดีกว่าJOINซึ่งจะได้รับกลุ่มเล็ก ๆ ของระเบียนเหล่านี้ทีละครั้งเป็นองค์ประกอบย่อยของแบบสอบถามอื่น จากนั้นฉันก็แยกวิเคราะห์ด้วยโค้ดฝั่งเซิร์ฟเวอร์ที่ดูเหมือน ...

<?php
    foreach($addresses as $address) {
         $persons[$address['Personid']]->Address[] = $address;
    }
?>

เมื่อไม่ใช้เข้าร่วมเพื่อเพิ่มประสิทธิภาพ

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

แต่JOINไม่มีประสิทธิภาพในการรับบันทึกที่มีความสัมพันธ์แบบหนึ่งต่อหลายคน

ตัวอย่าง: บล็อกฐานข้อมูลมี 3 ตารางที่น่าสนใจ Blogpost, Tag และข้อคิดเห็น

SELECT * from BlogPost
LEFT JOIN Tag ON Tag.BlogPostid = BlogPost.id
LEFT JOIN Comment ON Comment.BlogPostid = BlogPost.id;

หากมี 1 blogpost, 2 แท็กและ 2 ความคิดเห็นคุณจะได้รับผลลัพธ์เช่น:

Row1: tag1, comment1,
Row2: tag1, comment2,
Row3: tag2, comment1,
Row4: tag2, comment2,

สังเกตว่าแต่ละระเบียนซ้ำกันอย่างไร ตกลงดังนั้น 2 ความคิดเห็นและ 2 แท็กคือ 4 แถว ถ้าเรามี 4 ความคิดเห็นและ 4 แท็กล่ะ? คุณไม่ได้ 8 แถว - คุณได้ 16 แถว:

Row1: tag1, comment1,
Row2: tag1, comment2,
Row3: tag1, comment3,
Row4: tag1, comment4,
Row5: tag2, comment1,
Row6: tag2, comment2,
Row7: tag2, comment3,
Row8: tag2, comment4,
Row9: tag3, comment1,
Row10: tag3, comment2,
Row11: tag3, comment3,
Row12: tag3, comment4,
Row13: tag4, comment1,
Row14: tag4, comment2,
Row15: tag4, comment3,
Row16: tag4, comment4,

เพิ่มตารางเพิ่มเติมระเบียนเพิ่มเติม ฯลฯ และปัญหาจะขยายไปอย่างรวดเร็วไปยังหลายร้อยแถวที่เต็มไปด้วยข้อมูลที่ซ้ำซ้อนส่วนใหญ่

สิ่งที่ซ้ำซ้อนเหล่านี้มีค่าใช้จ่ายเท่าใด หน่วยความจำ (ในเซิร์ฟเวอร์ SQL และรหัสที่พยายามลบรายการที่ซ้ำกัน) และทรัพยากรระบบเครือข่าย (ระหว่างเซิร์ฟเวอร์ SQL และเซิร์ฟเวอร์รหัสของคุณ)

ที่มา: https://dev.mysql.com/doc/refman/8.0/en/nested-join-optimization.html ; https://dev.mysql.com/doc/workbench/en/wb-relationship-tools.html


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

@cHao: ขอบคุณสำหรับความคิดเห็นของคุณ คำตอบของฉันข้างต้นเป็นบทสรุปของเอกสาร MySQL ที่นี่: dev.mysql.com/doc/workbench/en/wb-relationship-tools.html
HoldOffHunger

นั่นไม่ใช่เอกสาร MySQL มันเป็นเอกสารสำหรับเครื่องมือ GUI เฉพาะสำหรับการทำงานกับฐานข้อมูล MySQL และมันก็ไม่ได้ให้คำแนะนำใด ๆ เมื่อการเข้าร่วมนั้นเหมาะสม
cHao

@cHao: ขออภัยฉันหมายถึงเอกสาร MySQL (R) สำหรับ MySQL WorkBench (TM) ไม่ใช่ MySQL Server (TM)
HoldOffHunger

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

8

สร้างทั้งแบบสอบถามที่แยกจากกันและเข้าร่วมจากนั้นตั้งเวลาแต่ละคำถาม - ไม่มีสิ่งใดที่ช่วยได้มากกว่าจำนวนจริง

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


7

ขึ้นอยู่กับความซับซ้อนของฐานข้อมูลเมื่อเทียบกับความซับซ้อนของนักพัฒนามันอาจจะง่ายกว่าในการโทรด้วย SELECT จำนวนมาก

ลองรันสถิติฐานข้อมูลกับทั้ง JOIN และ SELECTS ดูว่าในสภาพแวดล้อมของคุณเข้าร่วมเร็วกว่าหรือช้ากว่า SELECT

จากนั้นอีกครั้งหากเปลี่ยนเป็น JOIN จะหมายถึงการทำงานเสริมวัน / สัปดาห์ / เดือนพิเศษฉันจะใช้งาน SELECT หลายอัน

ไชโย

BLT


5

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

เมื่อมีการโต้ตอบกับฐานข้อมูลจากแอปพลิเคชันอื่นเช่น PHP จะมีการโต้แย้งหนึ่งครั้งในการเดินทางไปยังเซิร์ฟเวอร์ในหลาย ๆ

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

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

ย่อหน้าสุดท้ายเป็นความเห็นส่วนตัว แต่ฉันหวังว่านี่จะช่วยได้ ฉันเห็นด้วยกับคนอื่น ๆ แม้ว่าใครจะบอกว่าคุณควรเป็นมาตรฐาน ทั้งสองวิธีคือกระสุนเงิน


ใช่เราควรบัญชีไม่เพียง แต่สำหรับแบบสอบถามตัวเอง แต่ยังสำหรับการประมวลผลข้อมูลภายในแอปพลิเคชัน หากดึงข้อมูลด้วยการรวมภายนอกมีความซ้ำซ้อน (บางครั้งอาจมีขนาดใหญ่มาก) ซึ่งจะต้องแยกออกโดยแอป (โดยปกติในห้องสมุด ORM บางแห่ง) ดังนั้นโดยสรุปการเลือก SELECT เดียวด้วยแบบสอบถาม JOIN อาจใช้ CPU มากขึ้นและ เวลากว่าเลือกง่ายสองแบบ
JustAMartin

4

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

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

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

+------------+     +---------+     +---------+
|  comment   |     |   post  |     |  tag    |
|------------|*   1|---------|1   *|---------|
| post_id    |-----| post_id |-----| post_id |
| comment_id |     | ...     |     | tag_id  |
| user_id    |     |         |     | ...     |
| ...        |     |         |     | ...     |
+------------+     +---------+     +---------+

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

ลองพิจารณาสถานการณ์ที่แตกต่างกัน: คุณต้องการความคิดเห็นที่แนบมากับโพสต์และข้อมูลการติดต่อของผู้แสดงความคิดเห็น

 +----------+     +------------+     +---------+
 |   user   |     |  comment   |     |   post  |
 |----------|1   *|------------|*   1|---------|
 | user_id  |-----| post_id    |-----| post_id |
 | username |     | user_id    |     | ...     |
 | ...      |     | ...        |     +---------+
 +----------+     +------------+

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


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

@AdrianBaker: อย่างที่ฉันบอกคนเก่ง ๆ มากมายที่ทำงานหนักถ้าฉันจะปรับ SQL Server ของฉันให้ดีความคิดแรกของฉันคือใช้การบีบอัดซึ่งจะขจัดความซ้ำซ้อนจำนวนมากโดยไม่ต้องเปลี่ยนรหัส มากเลย การปรับให้เหมาะสมในระดับต่อไปจะรวมถึงการจัดระเบียบผลลัพธ์ใหม่ในตารางและส่งสิ่งเหล่านั้นพร้อมกับ tuples ของแถวรหัสซึ่งห้องสมุดลูกค้าสามารถรวบรวมด้านข้างได้อย่างง่ายดายตามต้องการ
cHao

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

3

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


2

นี่คือลิงค์ที่มี 100 ข้อความค้นหาที่เป็นประโยชน์เหล่านี้ทดสอบในฐานข้อมูล Oracle แต่จำไว้ว่า SQL เป็นมาตรฐานสิ่งที่แตกต่างระหว่าง Oracle, MS SQL Server, MySQL และฐานข้อมูลอื่น ๆ คือภาษา SQL:

http://javaforlearn.com/100-sql-queries-learn/


1

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

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

ตัวเชื่อมจะดึงข้อมูลทั้งหมดในครั้งเดียว หากคุณกำลังสร้างรายงานหรือเติมกริดนี่อาจเป็นสิ่งที่คุณต้องการ คอมไพล์และ optomized เข้าร่วมก็จะเร็วกว่าเลือกเดียวในสถานการณ์นี้ จำไว้ว่าการรวม Ad-hoc นั้นอาจไม่เร็วคุณควรรวบรวมมัน (เป็น proc ที่เก็บไว้) คำตอบความเร็วขึ้นอยู่กับแผนการดำเนินการซึ่งรายละเอียดตรงกับขั้นตอนที่ DBMS ใช้ในการดึงข้อมูล


0

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

ทำไมไม่ลองทดสอบทั้งสองสถานการณ์คุณจะรู้แน่ ...

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