การสืบค้นแต่ละรายการเร็วกว่าการเข้าร่วมหรือไม่


44

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

TL : DR : หากคิวรีที่เข้าร่วมของฉันใช้เวลานานกว่ารันคิวรีแต่ละรายการนี่เป็นความผิดของฉันหรือเป็นสิ่งที่คาดหวัง

ก่อนอื่นฉันไม่ค่อยเข้าใจฐานข้อมูลมากนักดังนั้นอาจเป็นเพียงฉัน แต่ฉันสังเกตว่าเมื่อฉันต้องรับข้อมูลจากหลาย ๆ ตารางมันเร็วกว่าที่จะได้รับข้อมูลนี้จากการสืบค้นหลายรายการในตารางแต่ละรายการ มีการรวม Inner ง่ายๆ) และแก้ไขข้อมูลร่วมกันบนฝั่งไคลเอ็นต์ที่พยายามเขียนแบบสอบถามแบบซับซ้อน (ซับซ้อน) ที่ฉันสามารถรับข้อมูลทั้งหมดในแบบสอบถามเดียว

ฉันพยายามใส่ตัวอย่างง่ายๆอย่างหนึ่งไว้ด้วยกัน:

ซอ Fiddle

การตั้งค่าสคีมา :

CREATE TABLE MASTER 
( ID INT NOT NULL
, NAME VARCHAR2(42 CHAR) NOT NULL
, CONSTRAINT PK_MASTER PRIMARY KEY (ID)
);

CREATE TABLE DATA
( ID INT NOT NULL
, MASTER_ID INT NOT NULL
, VALUE NUMBER
, CONSTRAINT PK_DATA PRIMARY KEY (ID)
, CONSTRAINT FK_DATA_MASTER FOREIGN KEY (MASTER_ID) REFERENCES MASTER (ID)
);

INSERT INTO MASTER values (1, 'One');
INSERT INTO MASTER values (2, 'Two');
INSERT INTO MASTER values (3, 'Three');

CREATE SEQUENCE SEQ_DATA_ID;

INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.3);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.5);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.7);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 2, 2.3);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 3, 3.14);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 3, 3.7);

ข้อความค้นหา A :

select NAME from MASTER
where ID = 1

ผลลัพธ์ :

| NAME |
--------
|  One |

ข้อความค้นหา B :

select ID, VALUE from DATA
where MASTER_ID = 1

ผลลัพธ์ :

| ID | VALUE |
--------------
|  1 |   1.3 |
|  2 |   1.5 |
|  3 |   1.7 |

ข้อความค้นหา C :

select M.NAME, D.ID, D.VALUE 
from MASTER M INNER JOIN DATA D ON M.ID=D.MASTER_ID
where M.ID = 1

ผลลัพธ์ :

| NAME | ID | VALUE |
---------------------
|  One |  1 |   1.3 |
|  One |  2 |   1.5 |
|  One |  3 |   1.7 |

แน่นอนฉันไม่ได้วัดประสิทธิภาพใด ๆ กับสิ่งเหล่านี้ แต่อย่างใดอย่างหนึ่งอาจสังเกต:

  • Query A + B ส่งคืนข้อมูลที่สามารถใช้งานได้เท่ากับ Query C
  • A + B ต้องส่งคืน 1 + 2x3 == 7 "Data Cells" ให้กับลูกค้า
  • C ต้องส่งคืน 3x3 == 9 "Data Cells" ให้กับลูกค้าเนื่องจากการเข้าร่วม I โดยธรรมชาติแล้วจะรวมความซ้ำซ้อนบางอย่างในชุดผลลัพธ์

การสรุปจากสิ่งนี้ (เท่าที่ทำได้):

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

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


ความคิดเห็นไม่ได้มีไว้สำหรับการอภิปรายเพิ่มเติม การสนทนานี้ได้รับการย้ายไปแชท
Jack Douglas

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

คำตอบ:


45

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

ในสถานการณ์ประสิทธิภาพใด ๆ คุณจะต้องทดสอบและวัดผลโซลูชันเพื่อดูว่าเร็วกว่าใด

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

ฉันสังเกตเห็นว่าเมื่อฉันต้องรับข้อมูลจากหลาย ๆ ตารางมันจะ "เร็วขึ้น" ในการรับข้อมูลนี้ผ่านการสืบค้นหลายครั้งในแต่ละตาราง (อาจมีการรวมด้านในอย่างง่าย) และแก้ไขข้อมูลเข้าด้วยกันในฝั่งไคลเอ็นต์ เพื่อเขียนแบบสอบถามแบบซับซ้อน (เข้าร่วม) ซึ่งฉันสามารถรับข้อมูลทั้งหมดในแบบสอบถามเดียว

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

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

โดยปกติจะไม่เป็นเช่นนั้น เวลาส่วนใหญ่แม้ว่าชุดอินพุตมีขนาดใหญ่ชุดผลลัพธ์จะเล็กกว่าผลรวมของอินพุตมาก

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

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

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

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

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

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

สิ่งหนึ่งที่ไม่ได้ถูกกล่าวถึงคือการรักษาความสอดคล้องของข้อมูลที่ส่งคืนจากฐานข้อมูล หากมีการใช้แบบสอบถามแยกต่างหากมีแนวโน้มมากขึ้น (เนื่องจากปัจจัยหลายอย่าง) ที่จะส่งคืนข้อมูลที่ไม่สอดคล้องกันยกเว้นว่ามีการใช้รูปแบบของการแยกสแน็ปช็อตทุกชุดของแบบสอบถาม


+1 สำหรับแบนด์วิดท์เครือข่ายเป็นทรัพยากรที่ จำกัด
Hari Harker

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

6

แน่นอนฉันไม่ได้วัดประสิทธิภาพการทำงานใด ๆ กับสิ่งเหล่านี้

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

เมื่อคุณเพิ่มข้อมูลความเร็วของการสืบค้นหนึ่งและสองจะแตกต่างกัน แต่การเข้าร่วมฐานข้อมูลจะยังเร็วกว่า

คุณควรพิจารณาว่าจะเกิดอะไรขึ้นหากการรวมภายในเป็นการกำจัดข้อมูล


2

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

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

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


-3

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

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


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

2
คุณอาจต้องการพิจารณาว่าเลเยอร์เครือข่ายมีการบีบอัดหรือไม่ SQL * Net ของ Oracle ทำในค่าที่ทำซ้ำในคอลัมน์เดียวกันซึ่งถูกบีบอัดอย่างมีประสิทธิภาพ
David Aldridge

3
@ TomTom คุณอาจมีจุดหรือไม่ (เช่นคะแนน David Aldridge เรื่องบีบอัด) แต่ถ้อยคำของคุณสับสน "เครือข่ายไร้ประสิทธิภาพของการเข้าร่วม" ? จริงๆแล้วแก้ไขให้ชัดเจนว่าคุณหมายถึงอะไร
ypercubeᵀᴹ

@ChrisSaxon แน่ใจว่ามีภาพที่คุณมีตารางสำหรับรายงาน "ชื่อ -> ฐาน -> ตารางแถว" และคุณต้องการแถวทั้งหมดเพื่อให้คุณเข้าร่วม 3 ตารางเหล่านี้ แต่ละตารางมี varchars ยาวดังนั้นสิ่งที่เกิดขึ้นคือทุกแถวที่คุณทำซ้ำ varchars ยาวเหล่านี้ ชั้นแอปพลิเคชันจำเป็นต้องจัดสรรหน่วยความจำสำหรับสตริงเหล่านี้ทั้งหมดแล้วจัดกลุ่มให้เป็นแบบจำลองของคุณ ดังนั้นฉันคิดว่านั่นคือสิ่งที่เขาหมายถึงมีข้อมูลมากขึ้นส่ง
ไมค์

@MIKE ที่ขึ้นอยู่กับนิพจน์ที่คุณเลือกไม่ใช่การเข้าร่วม และอาจมีการบีบอัดเครือข่าย ใน Oracle Database SQL * Net จะลบค่าที่ซ้ำกันซ้ำ ๆnicetheory.io/2018/01/11/…
Chris Saxon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.