การทำ Normalization ของฐานข้อมูลสรุปได้ในประโยคเดียว: "ข้อเท็จจริงเดียวกันต้องเก็บไว้แค่ที่เดียวเท่านั้น" วิธีทำอย่างเป็นระบบก็คือ 1NF → 2NF → 3NF

ทำไมถึงสำคัญ? — เพราะถ้าข้อมูลเดียวกันกระจายอยู่หลายแถว พอแก้แค่บางที่แล้วลืมแก้อีกที่ ข้อมูลก็จะขัดแย้งกันทันที ปัญหานี้เรียกว่า update anomaly ลองดูด้วยตัวเองด้านล่างได้เลย

Update Anomaly — Try It

Prof.A moved to Room 502. Click the cell to update it. Notice: you have to change every row — miss one and the data contradicts itself.

Before (unnormalized)
studentcourseinstructorofficegrade
S1 KimMATH101Prof.ARoom 301 ← clickA
S1 KimCS102Prof.BRoom 405B+
S2 LeeCS102Prof.BRoom 405A
S3 ParkMATH101Prof.ARoom 301 ← clickB
0/2 updated
After (3NF)
Instructorsinstructor_idinstructor_office
Prof.ARoom 502
Prof.BRoom 405
In 3NF, you update exactly 1 row in the Instructors table. Done.

ถ้าห้องแล็บของ 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)
Functional Dependencies at a Glance

Enrollment(student_id, course_id, student_name, course_title, instructor_id, instructor_office, grade)

student_idPrimary Keycourse_idPrimary Keystudent_namecourse_titleinstructor_idinstructor_officegrade
Full dependency (on entire key)Partial dependency (on part of key)Transitive dependency (via non-key)

การกำจัดลูกศรสีเหลืองและสีแดง = การแยกตาราง = การทำ Normalization

ดู 1NF → 2NF → 3NF แบบรวดเดียว

ด้านล่างนี้ลองคลิกดูได้เลยว่า ตารางถูกแยกออกทีละขั้นอย่างไร เซลล์สีแดงหมายถึง "คอลัมน์นี้ไม่ควรอยู่ตรงนี้"

Normalization Step-by-Step
Everything in one table. Multiple values in one cell.
Enrollment
student_id 🔑student_namecoursesgrades
S1KimMATH101, CS102A, B+
S2LeeCS102A
S3ParkMATH101, CS102, PHY201B, A, A-
Problem: courses column has multiple values crammed into one cell.
Fix: Split into one row per student-course pair.

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 ก็ควรรู้ก่อนว่ากำลังยอมแลกอะไรไป

ลองตรวจตารางของตัวเองดู

เลือกมาหนึ่งตารางจากโปรเจกต์ของคุณ แล้วทำตามนี้:

  1. เขียนก่อนว่าคีย์คืออะไร
  2. ตรวจว่าแต่ละ non-key column ขึ้นอยู่กับคีย์ทั้งหมด หรือแค่บางส่วน → ถ้าเป็นบางส่วน แปลว่าผิด 2NF
  3. ตรวจว่า non-key column ไปขึ้นอยู่กับ non-key column อื่นหรือไม่ → ถ้ามี แปลว่าผิด 3NF

แค่ 3 ขั้นตอนนี้ก็ช่วยจับปัญหา Normalization ได้เกือบทั้งหมดแล้ว

ต้องการความช่วยเหลือในการแก้โจทย์?

อัปโหลดคำถามของคุณแล้วรับคำตอบแบบทีละขั้นตอนที่ผ่านการตรวจสอบในไม่กี่วินาที

เปิด GPAI Solver →