နားလည်ထားရမယ့် အချက်
Database schema တစ်ခု ဒီဇိုင်းဆွဲခြင်းဟာ ချက်ချင်း idea တစ်ခုတည်းနဲ့ ပြီးတာ မဟုတ်ပါဘူး — ထပ်ခါထပ်ခါ လုပ်နိုင်တဲ့ ဆုံးဖြတ်ချက်တွေ အဆက်အစပ်ပါ။ ဒီအတိုင်းသဘောထားမှသာ production ထဲမှာ တည်တံ့တဲ့ schema နဲ့ ခြောက်လအတွင်း ပြန်ရေးရမယ့် schema ကို ခွဲခြားနိုင်မှာပါ။
Table တွေနဲ့ column တွေထဲ ချက်ချင်းမဆင်းသွားဘဲ၊ အတွေ့အကြုံရှိတဲ့ team တွေက requirements စုဆောင်းခြင်းမှ data အစစ်နဲ့ design ကို စမ်းသပ်ခြင်းအထိ အဆင့် ၉ ဆင့်ကို အမြဲတမ်း အတူတူ လုပ်ကြပါတယ်။
၁။ Requirements
System ဘာလုပ်ရမလဲကို ရိုးရှင်းသောစာသားနဲ့ ချရေးပါ: user တွေက course ကြည့်ပြီး enroll လုပ်တယ်၊ instructor တွေက lesson ဖန်တီးတယ်၊ app က completion ကို track လုပ်တယ်။
၂။ Entity များရှာဖွေခြင်း
Table သီးသန့်ထိုက်တန်တဲ့ noun တွေကို ထုတ်ယူပါ: User, Course, Lesson, Enrollment, Progress, Bookmark။
၃။ Field များသတ်မှတ်ခြင်း
Entity တစ်ခုစီကို attribute ပေးပါ: User မှာ email နဲ့ name ရှိမယ်၊ Lesson မှာ title၊ order၊ content ရှိမယ်။
၄။ Key ရွေးချယ်ခြင်း
Table တိုင်းကို primary key (id အများအားဖြင့်) ပေးပြီး Lesson က Course ကို ပြန်ညွှန်းနိုင်ဖို့ foreign key သုံးပါ။
၅။ Relationship သတ်မှတ်ခြင်း
Course တစ်ခုမှာ Lesson များစွာ ရှိမယ်၊ User နဲ့ Course က Enrollment မှတစ်ဆင့် ချိတ်ဆက်မယ်၊ User တစ်ဦးမှာ Progress row များစွာ ရှိမယ်။
၆။ Constraint ထည့်ခြင်း
User မှာ email လိုအပ်စေပြီး unique ဖြစ်စေပါ၊ Lesson တစ်ခုစီက Course တစ်ခုနဲ့ အမြဲပါဝင်ရမယ်လို့ သတ်မှတ်ပါ။
၇။ Query ဒီဇိုင်းဆွဲခြင်း
App run မယ့် query အစစ်တွေကို ချရေးပါ: course တစ်ခုအတွက် lesson အားလုံးရယူခြင်း၊ course တစ်ခုအတွင်း user တစ်ဦးရဲ့ progress ရယူခြင်း။
၈။ Index ထည့်ခြင်း
အဲဒီ query တွေ filter လုပ်တဲ့ foreign key တွေကို index လုပ်ပါ၊ ဥပမာ Lesson ပေါ်က course_id၊ Progress ပေါ်က user_id။
၉။ စမ်းသပ်ခြင်း
လက်တွေ့ဆန်တဲ့ data ကို load လုပ်ပြီး query အစစ်တွေကို run ကြည့်ပါ၊ ရလဒ်တွေမှန်ကန်ပြီး လုံလောက်စွာမြန်လား စစ်ပါ။
Query နဲ့ index တွေက အစမှာမဟုတ်ဘဲ အဆုံးနားမှာ ရောက်လာတာကို သတိပြုပါ — app က database ကို ဘာမေးမလဲသိမှသာ index ကောင်းကောင်းကို ရွေးနိုင်မှာပါ။
SCHEMA DESIGN WORKFLOW
----------------------
1. Requirements -> what must the system do?
|
2. Identify Entities -> User, Course, Lesson, Enrollment...
|
3. Define Fields -> attributes per entity
|
4. Choose Keys -> primary keys, foreign keys
|
5. Define Relations -> one-to-many, many-to-many
|
6. Add Constraints -> required, unique, not null
|
7. Design Queries -> what will the app actually ask?
|
8. Add Indexes -> speed up those specific queries
|
9. Test -> real data, real queries, verifyလက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
Workflow ကို learning platform တစ်ခုအပေါ် အသုံးချကြည့်ရင် ပိုတိကျလာပါတယ်။ Plain-English requirements အနည်းငယ်ထဲက entity တွေက တိုက်ရိုက် ပေါ်လာပါတယ်: User, Course, Lesson, Enrollment, Progress, Bookmark။
လွတ်တတ်သောအချက်
Enrollment နဲ့ Progress တို့ကို ကြည့်တာနဲ့ ရိုးရိုး relationship လိုပဲ ထင်ရပါတယ်။ တစ်ခုစီက field သီးသန့် (enrollment date, completion timestamp) လိုအပ်တာကြောင့် foreign key တစ်ခုတည်းမက table သီးသန့် ထိုက်တန်ပါတယ်။
Constraint တွေက raw structure အပေါ်မှာ လက်တွေ့ စည်းမျဉ်း ထပ်ထည့်ပေးပါတယ် — Lesson တစ်ခုက Course တစ်ခုတည်းနဲ့ ပါဝင်ရမယ်၊ user တစ်ယောက် course တစ်ခုတည်းကို နှစ်ခါ enroll လုပ်လို့ မရသင့်ပါဘူး။
အောက်က code ဥပမာက step နှစ်ချက်ရဲ့ ရိုးရှင်းထားတဲ့ version ကို အသုံးချထားပါတယ် — requirements list ကို candidate entity list အဖြစ် ပြောင်းပေးတာပါ။ တမင်ရိုးရှင်းအောင် ဖန်တီးထားတာမို့ session အစစ်မှာတော့ ရှာတွေ့တာတွေကို လူတစ်ယောက်က review, merge, rename လုပ်ဖို့ လိုနေဆဲပါ။
အတူတူ စမ်းရေးကြည့်မယ်
function extractCandidateEntities(requirements) {
// Illustrative heuristic only -- NOT real NLP. It just looks for known
// domain-noun keywords so you have a starting list to refine by hand.
const knownNouns = {
user: "user", users: "user",
course: "course", courses: "course",
lesson: "lesson", lessons: "lesson",
enrollment: "enrollment", enrollments: "enrollment",
progress: "progress",
bookmark: "bookmark", bookmarks: "bookmark",
instructor: "instructor", instructors: "instructor"
};
const nounPattern = new RegExp("\\b(" + Object.keys(knownNouns).join("|") + ")\\b", "gi");
const counts = {};
for (const req of requirements) {
const matches = req.match(nounPattern) || [];
for (const m of matches) {
const key = knownNouns[m.toLowerCase()];
counts[key] = (counts[key] || 0) + 1;
}
}
return Object.entries(counts)
.sort((a, b) => b[1] - a[1])
.map(([entity, mentions]) => ({ entity, mentions }));
}
const requirements = [
"Users can browse and enroll in courses",
"Each course has multiple lessons in a fixed order",
"The app tracks a user's progress through each lesson",
"Users can bookmark a lesson to return to later",
"Instructors create courses and lessons",
"An enrollment links one user to one course"
];
console.log(JSON.stringify(extractCandidateEntities(requirements), null, 2));Function က requirement string ခြောက်ခုကို scan လုပ်ပြီး သိထားတဲ့ domain keyword တစ်ခုစီကို ရေတွက်ကာ mention အရေအတွက်အလိုက် စီထားတဲ့ candidate entity list ကို ပြန်ပေးပါတယ်: user (4), course (4), lesson (4), progress (1), bookmark (1), instructor (1), enrollment (1)။ Trailing 's' ကို မသေချာဘဲ ဖြတ်ပစ်တာမျိုးမဟုတ်ဘဲ သိထားတဲ့ singular/plural form တွေကို တိတိကျကျ map လုပ်ထားတာမို့ 'progress' ကို 'progres' ဖြစ်သွားတဲ့ ရိုးရာ stemming bug ကို ရှောင်နိုင်ပါတယ်။၅ မိနစ် စမ်းကြည့်
Requirements array ထဲကို "Instructors can leave feedback comments on a lesson" လို requirement string အသစ်တစ်ခု ထည့်ပြီး code ကို ပြန် run ကြည့်ပါ။ Entity အသစ် ဘာပေါ်လာလဲ။ Foreign key ရိုးရိုးထက် ပိုတဲ့ field လိုအပ်လား စစ်ပြီး table သီးသန့် ထိုက်တန်လား ဆုံးဖြတ်ပါ။
သတိလေးတစ်ချက်
Requirements မချရေးခင် table နဲ့ column ထဲ ချက်ချင်း ဆင်းသွားခြင်းက ဘယ်သူ့ တကယ့်မေးခွန်းနဲ့မှ မကိုက်ညီတဲ့ schema ကို ဖြစ်စေတတ်ပါတယ်။
Query အစစ်မရှိသေးခင် index ကို ခန့်မှန်းပြီး ဒီဇိုင်းဆွဲခြင်းက step ခုနစ်ကနေ app က ဘာလိုအပ်လဲ ပေါ်လာမှသာ လုပ်သင့်ပါတယ်။
Wikipedia: Database design — How Databases Work