มันจะเป็นการดีกว่าหรือที่จะแยกเคียวรีใหญ่ออกเป็นเคียวรีเล็ก ๆ หลายรายการ?


13

มีสถานการณ์ที่ต้องมีแบบสอบถามที่ใหญ่มากเข้าร่วมหลายตารางพร้อมกับคำสั่งย่อยเลือกในพวกเขาเพื่อสร้างผลลัพธ์ที่ต้องการ

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

SELECT *
FROM   `users`
WHERE  `user_id` IN (SELECT f2.`friend_user_id`
                     FROM   `friends` AS f1
                            INNER JOIN `friends` AS f2
                              ON f1.`friend_user_id` = f2.`user_id`
                     WHERE  f2.`is_page` = 0
                            AND f1.`user_id` = "%1$d"
                            AND f2.`friend_user_id` != "%1$d"
                            AND f2.`friend_user_id` NOT IN (SELECT `friend_user_id`
                                                            FROM   `friends`
                                                            WHERE  `user_id` = "%1$d"))
       AND `user_id` NOT IN (SELECT `user_id`
                             FROM   `friend_requests`
                             WHERE  `friend_user_id` = "%1$d")
       AND `user_image` IS NOT NULL
ORDER  BY RAND() 
LIMIT %2$d

วิธีที่ดีที่สุดในการทำคืออะไร?

คำตอบ:


14

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

ปัญหาการบำรุงรักษา IME มาในเมื่อโครงสร้างของ SQL แบ่งลง แบบสอบถามแบบยาวที่ซับซ้อนในการเลือกย่อยทำให้การอ่านและการแก้ไขปัญหาต่ำลงเช่นเดียวกับมุมมองแบบอินไลน์และควรหลีกเลี่ยงคำถามทั้งสองนี้ในข้อความค้นหาแบบยาว ให้ใช้ VIEW แทนถ้าคุณทำได้ (โปรดสังเกตว่าถ้าคุณอยู่บน MySQL, วิวจะไม่ทำงานทั้งหมดที่ดี แต่สำหรับ db อื่น ๆ ส่วนใหญ่ที่พวกเขาทำ) และใช้นิพจน์ตารางทั่วไปที่ไม่ทำงาน (MySQL ไม่สนับสนุนสิ่งเหล่านี้ BTW)

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

เกี่ยวกับความสามารถในการปรับขนาดได้โปรดจำไว้ว่านักวางแผนมีความยืดหยุ่นมากขึ้นนั่นเป็นสิ่งที่ดีเช่นกัน ....

แก้ไข: คุณพูดถึงนี่คือ MySQL ดังนั้นมุมมองจึงไม่น่าจะทำงานได้ดีและ CTE นั้นไม่เป็นที่ต้องการ นอกจากนี้ตัวอย่างที่ให้มาไม่ได้ยาวหรือซับซ้อนเป็นพิเศษดังนั้นจึงไม่มีปัญหา


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

8

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

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


2
ข้อเสียของสตริงของเคียวรีแบบง่าย ๆ คือสถานะนั้นเปลี่ยนแปลงไปอย่างมีนัยสำคัญทำให้การดีบักโดยรวมของแอ็พพลิเคชันมีความซับซ้อนมากขึ้น นั่นคือคุณสามารถดีบักเคียวรี SQL ขนาดใหญ่ได้บ่อยเหมือนต้นไม้ แต่รหัสแอปพลิเคชันจะได้รับการดีบั๊กจากคำสั่งตรวจสอบว่าสถานะการเปลี่ยนแปลงในงบ ปัญหาที่แท้จริงเกี่ยวข้องกับความจริงที่ว่าการเลือกย่อยและมุมมองแบบอินไลน์ยังเป็นต้นไม้ของพวกเขาเอง .....
Chris Travers

ในกรณีของฉันคนเดียวที่ต้องจัดการ DB และรหัสคือตัวฉันเอง และส่วนใหญ่คำถามของฉันคือเกี่ยวกับจุดการค้นหา
Hamed Momeni

พวกคุณจะต้องดูวิธีที่ฉันเขียนกระบวนการชุดใหญ่ของฉัน แยกย่อยสิ่งต่างๆออกเป็นคำค้นหาง่าย ๆ ง่ายต่อการอ่าน ฉันลำเอียงเพราะคำค้นหาที่ฉันพยายามทำให้เป็นระเบียบมีความยาวมากกว่า 1,000 บรรทัดเป็นประจำ
datagod

5

2 เซ็นต์ของฉันสำหรับคำค้นหา 2 คำ - ประสิทธิภาพและความยืดหยุ่น:

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

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


2
RE: การอ้างอิง "SQL Server" ถึงแม้ว่า OP ไม่ได้ระบุ RDBMS ใด ๆ โดยเฉพาะฉันสงสัยว่ามันอยู่ใน MySQL จากเครื่องหมายขีดหลังและLIMIT
Martin Smith

@MartinSmith คุณสงสัยว่าถูกต้อง มันคือ MySQL
Hamed Momeni

2

บางครั้งไม่มีทางเลือกนอกจากแบ่งคิวรีใหญ่ / ซับซ้อนเป็นคิวรีขนาดเล็ก วิธีที่ดีที่สุดในการพิจารณาว่าจะใช้EXPLAINคำสั่งกับSELECTคำสั่ง จำนวนการติดตาม / สแกนที่ฐานข้อมูลของคุณจะทำการดึงข้อมูลของคุณคือผลิตภัณฑ์ของค่า "แถว" ที่ส่งคืนโดยEXPLAINแบบสอบถามของคุณ ในกรณีของเราเรามีแบบสอบถามเข้าร่วม 10 ตาราง สำหรับบันทึกโดยเฉพาะการติดตามมีจำนวน 409M ซึ่งบล็อก DB ของเราและผลักดันการใช้ CPU ของเซิร์ฟเวอร์ DB ของเรามากกว่า 300% เราสามารถดึงข้อมูลเดียวกันโดยแยกการสืบค้นได้เร็วขึ้นมาก

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

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