การทำ Normalization ของฐานข้อมูลสรุปได้ในประโยคเดียว: "ข้อเท็จจริงเดียวกันต้องเก็บไว้แค่ที่เดียวเท่านั้น" วิธีทำอย่างเป็นระบบก็คือ 1NF → 2NF → 3NF
ทำไมถึงสำคัญ? — เพราะถ้าข้อมูลเดียวกันกระจายอยู่หลายแถว พอแก้แค่บางที่แล้วลืมแก้อีกที่ ข้อมูลก็จะขัดแย้งกันทันที ปัญหานี้เรียกว่า update anomaly ลองดูด้วยตัวเองด้านล่างได้เลย
ถ้าห้องแล็บของ Prof.A เปลี่ยนไป ในตารางที่ยังไม่ normalized คุณต้องแก้ทั้ง 2 แถวด้วยมือทั้งหมด ถ้าพลาดไปแม้แต่แถวเดียว ก็จะเกิดความขัดแย้งว่า "Prof.A อยู่ทั้ง Room 301 และ Room 502" แต่ในตารางแบบ 3NF แก้แค่ 1 แถวก็จบ
นี่แหละคือทั้งหมดของ Normalization — ที่เหลือก็เป็นแค่กฎสำหรับตัดสินว่า "คอลัมน์ไหนควรอยู่ที่ไหน เพื่อให้ข้อมูลหนึ่งอย่างถูกเก็บไว้เพียงที่เดียว"
Functional dependency — เกณฑ์ตัดสินของ Normalization
Normalization จะพิจารณาว่า "คอลัมน์นี้ขึ้นอยู่กับอะไร" สิ่งนี้เรียกว่า functional dependency
ตัวอย่างเช่น student_id → student_name หมายความว่า "ถ้ารู้ student ID ก็จะรู้ชื่อได้"
ในแผนภาพด้านล่าง ให้ดูสีของลูกศร:
- สีเขียว = ขึ้นอยู่กับคีย์ทั้งหมด (ปกติ)
- สีเหลือง = ขึ้นอยู่กับแค่บางส่วนของคีย์ (partial dependency → ผิด 2NF)
- เส้นประสีแดง = ขึ้นอยู่ผ่าน non-key column อีกตัวหนึ่ง (transitive dependency → ผิด 3NF)
การกำจัดลูกศรสีเหลืองและสีแดง = การแยกตาราง = การทำ Normalization
ดู 1NF → 2NF → 3NF แบบรวดเดียว
ด้านล่างนี้ลองคลิกดูได้เลยว่า ตารางถูกแยกออกทีละขั้นอย่างไร เซลล์สีแดงหมายถึง "คอลัมน์นี้ไม่ควรอยู่ตรงนี้"
1NF: หนึ่งเซลล์มีได้หนึ่งค่า
ถ้าใส่หลายค่าไว้ในเซลล์เดียว เช่น MATH101, CS102 จะทั้งค้นหายากและ JOIN ก็ลำบาก
กฎ: ทุกเซลล์ต้องเป็น atomic (มีค่าเดียว)
คอลัมน์อย่าง phone1, phone2, phone3 ก็มีปัญหาแบบเดียวกัน — แค่เอาค่าไปซ่อนไว้ในชื่อคอลัมน์เท่านั้น
2NF: กำจัด partial dependency
ในตารางที่มี composite key เป็น (student_id, course_id) นั้น student_name จะขึ้นอยู่กับแค่ student_id เท่านั้น ไม่ได้ขึ้นอยู่กับคีย์ทั้งหมด แต่ขึ้นอยู่กับเพียงบางส่วน — นี่คือ partial functional dependency
กฎ: ทุก non-key column ต้องขึ้นอยู่กับ คีย์ทั้งหมด
ถ้ามี partial dependency ก็ให้ย้ายคอลัมน์นั้นออกไปเป็นอีกตารางหนึ่ง
ถ้าคีย์มีแค่คอลัมน์เดียวล่ะ? partial dependency จะเกิดไม่ได้อยู่แล้ว ดังนั้นถ้าเป็น 1NF ก็จะเป็น 2NF โดยอัตโนมัติ
3NF: กำจัด transitive dependency
ในตาราง Courses นั้น instructor_office ไม่ได้ขึ้นอยู่กับ course_id (คีย์) โดยตรง แต่ผ่านเส้นทาง course_id → instructor_id → instructor_office — นั่นคือ non-key column ไปขึ้นอยู่กับ non-key column อีกตัวหนึ่ง ซึ่งก็คือ transitive dependency
กฎ: non-key column ต้องขึ้นอยู่ผ่าน คีย์เท่านั้น ห้ามผ่าน non-key column อื่น
วิธีแก้: แยก instructor_office ออกไปไว้ในตาราง Instructors
แทนที่จะท่องจำ ให้ถามแค่คำถามเดียว
"ทุก non-key attribute ต้องขึ้นอยู่กับ the key, the whole key, and nothing but the key"
ประโยคนี้ครอบคลุมทั้งหมด:
- the key = 1NF (ข้อเท็จจริงต้องระบุได้ด้วยคีย์)
- the whole key = 2NF (ต้องขึ้นอยู่กับคีย์ทั้งหมด ไม่ใช่แค่บางส่วน)
- and nothing but the key = 3NF (ต้องขึ้นอยู่กับคีย์โดยตรง ไม่ผ่าน non-key column)
เวลาเจอโจทย์เรื่อง Normalization ในข้อสอบ ให้ถามแค่นี้: "คอลัมน์นี้ขึ้นอยู่กับอะไร? คีย์ทั้งหมด, บางส่วนของคีย์, หรือ non-key column?"
ข้อผิดพลาดที่พบบ่อย
"ทำถึง 3NF ก็จบแล้ว" — 3NF เป็นจุดเริ่มต้นที่ดี แต่ไม่ใช่จุดจบ บางกรณีอาจต้องใช้ BCNF ที่เข้มงวดกว่า หรือในทางกลับกัน บางครั้งก็จงใจ denormalize เพื่อประสิทธิภาพ
"ยิ่งแยกตารางเยอะยิ่งดี" — เป้าหมายของ Normalization ไม่ใช่การเพิ่มจำนวนตาราง แต่คือการทำให้ "แต่ละตารางรับผิดชอบข้อเท็จจริงเพียงประเภทเดียว" ถ้าแยกโดยไม่มีเหตุผลด้าน dependency ก็จะทำให้ JOIN ซับซ้อนขึ้นเปล่าๆ
"ถ้าเป็น NoSQL ก็ไม่ต้องทำ Normalization" — แม้คำว่า Normalization จะเป็นคำเฉพาะของ relational DB แต่ปัญหาเรื่อง "การรักษาความสอดคล้องของข้อมูลซ้ำ" มีอยู่ในทุก DB ตอนจะ denormalize ก็ควรรู้ก่อนว่ากำลังยอมแลกอะไรไป
ลองตรวจตารางของตัวเองดู
เลือกมาหนึ่งตารางจากโปรเจกต์ของคุณ แล้วทำตามนี้:
- เขียนก่อนว่าคีย์คืออะไร
- ตรวจว่าแต่ละ non-key column ขึ้นอยู่กับคีย์ทั้งหมด หรือแค่บางส่วน → ถ้าเป็นบางส่วน แปลว่าผิด 2NF
- ตรวจว่า non-key column ไปขึ้นอยู่กับ non-key column อื่นหรือไม่ → ถ้ามี แปลว่าผิด 3NF
แค่ 3 ขั้นตอนนี้ก็ช่วยจับปัญหา Normalization ได้เกือบทั้งหมดแล้ว
ต้องการความช่วยเหลือในการแก้โจทย์?
อัปโหลดคำถามของคุณแล้วรับคำตอบแบบทีละขั้นตอนที่ผ่านการตรวจสอบในไม่กี่วินาที
เปิด GPAI Solver →