GORAGOD.com

การรวมข้อมูลจากหลายตารางด้วย OUTER JOIN

คำสั่ง OUTER JOIN ของ MySQL มีอยู่ 2 รูปแบบคือ LEFT OUTER JOIN (หรือ LEFT JOIN) และ RIGHT OUTER JOIN (หรือ RIGHT JOIN) โดยที่คำสั่งในกลุ่มนี้จะเป็นการ Query โดยการจับคู่ข้อมูลจาก 2 ตาราง โดยรักษาข้อมูลในตารางหลักไว้ และคืนค่า NULL ในฟิลด์ที่ไม่สามารถจับคู่ได้หรือหากไม่พบข้อมูลในตารางรอง หรือจะอธิบายอีกแบบว่า เราจะได้ทุก record ออกมาจากตารางหลักนั่นเอง ดังแผนภาพด้านล่าง
SELECT U.id,U.email,E.sent FROM db_user AS U LEFT JOIN db_email AS E ON E.member_id=U.id

จากตัวอย่างการ JOIN ข้างบนเราจะได้ข้อมูลทุก record ของตาราง user (รายชื่ออีเมล์สมาชิกทุกคน) โดยจับคู่กับตาราง email โดยที่ถ้าพบว่า E.member_id=U.id แสดงว่าอีเมล์นี้มีการส่งแล้ว โดยคืนค่าเวลาที่ส่งที่ฟิลด์ sent ของตาราง db_email(หากยังไม่ได้ส่งฟิลด์นี้จะเป็น NULL)
สิ่งที่ควรจำสำหรับการ JOIN แบบนี้คือ เงือนไขการ JOIN จะต้องถูกใส่ไว้ใน ON เท่านั้น ส่วนเงื่อนไขการค้นหาให้ใส่ไว้ในคำสั่ง WHERE เท่านั้นเช่นกัน

ปัญหาการใช้งาน OUTER JOIN

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

การแก้ปัญหานี้อาจต้องใช้วิธีการ query ในรูปแบบอื่น
SELECT * (
(SELECT U.id,U.email,E.sent FROM db_user AS U INNER JOIN db_email AS E ON E.member_id=U.id)
UNION ALL
(SELECT U.id,U.email,0 FROM db_user)
} AS Q GROUP BY Q.id

อธิบายได้ดังนี้นะครับ คำสั่ง SELECT U.id,U.email,E.sent FROM db_user AS U INNER JOIN db_email AS E ON E.member_id=U.id จะเลือกเฉพาะรายชื่อที่สามารถจับคู่ได้ หรือรายชื่อที่ส่งแล้วเท่านั้น ในขณะที่ SELECT U.id,U.email,0 FROM db_user จะทำการเลือกรายชื่อสมาชิกทุกคน แล้วนำผลลัพท์ของทั้ง 2 query ที่ซ้ำกัน โดยใช้ UNION ALL (ผมใช้ UNION ALL เพราะมีประสิทธิภาพมากกว่า UNION เนื่องจากไม่จำเป็นต้องตัด record ที่ซ้ำกัน) และมาทำการตัด record ที่ซ้ำกันอีกครั้งด้วย GROUP BY ที่ query ชั้นนอกสุด