Skip to content
← All Skills
🗄️

Database Design

Data & Messaging

Schema design, normalization, indexing strategy, audit trail patterns สำหรับ financial/trading systems

What I Can Do

  • ออกแบบ database schema ตั้งแต่ ERD จนถึง production-ready DDL
  • Apply normalization (1NF–3NF) และรู้ว่าเมื่อไหร่ควร denormalize
  • ออกแบบ indexing strategy ให้เหมาะกับ query patterns
  • Design audit trail, soft delete, multi-tenancy patterns
  • วางแผน schema migration ที่ไม่กระทบ production

Entity & Attribute

  • Entity = สิ่งที่ต้องเก็บข้อมูล เช่น User, Order, Product → กลายเป็น table
  • Attribute = คุณสมบัติของ entity เช่น email, status, price → กลายเป็น column
  • เลือก data type ให้เหมาะกับ attribute เช่น DECIMAL สำหรับเงิน ไม่ใช่ FLOAT

Primary Key & Foreign Key

  • Primary Key — unique identifier ของแต่ละ row, ต้องไม่ซ้ำและไม่เป็น NULL
  • Foreign Key — column ที่ reference primary key ของ table อื่น, enforce referential integrity

1-to-1 / 1-to-Many / Many-to-Many

  • 1-to-1 — user ↔ profile (foreign key + UNIQUE constraint)
  • 1-to-Many — user ↔ orders (foreign key ฝั่ง many)
  • Many-to-Many — users ↔ roles (ใช้ junction table user_roles)

ER Diagram Basics

Entity-Relationship Diagram แสดง entities, attributes, และ relationships — ใช้ตอนออกแบบเพื่อให้ทีมเห็นภาพรวมก่อนเขียน DDL

Data Types Selection

เลือก data type ให้เหมาะสม:

  • เงิน → DECIMAL(20,8) (ไม่ใช่ FLOAT เพราะ precision loss)
  • เวลา → TIMESTAMPTZ (ไม่ใช่ TIMESTAMP เพราะไม่มี timezone)
  • ID → UUID (distributed-friendly) หรือ BIGSERIAL (simple, sequential)
  • สถานะ → ENUM หรือ VARCHAR + CHECK

NOT NULL & DEFAULT

  • NOT NULL — force ให้ทุก row ต้องมีค่า, ป้องกัน data quality issues
  • DEFAULT NOW() — ให้ค่า default อัตโนมัติ ลด burden จาก application layer

Normalization (1NF, 2NF, 3NF)

  • 1NF — ไม่มี repeating groups, แต่ละ column มี atomic value
  • 2NF — 1NF + ทุก non-key column depend on whole primary key (ไม่ใช่แค่บางส่วน)
  • 3NF — 2NF + ไม่มี transitive dependency (non-key column ไม่ depend on non-key column อื่น)

Denormalization Trade-offs

Denormalize เมื่อ read performance สำคัญกว่า write consistency — เช่น สร้าง summary table สำหรับ dashboard ที่ JOIN หลาย tables แพงเกินไป trade-off คือ data อาจ stale และ update ยากขึ้น

Indexing Basics (When & Why)

  • สร้าง index บน columns ที่ใช้ใน WHERE, JOIN, ORDER BY บ่อย
  • ไม่ index ทุก column — แต่ละ index เพิ่ม overhead ตอน INSERT/UPDATE
  • ตรวจ query plan (EXPLAIN) เพื่อยืนยันว่า index ถูกใช้จริง

Composite Keys

Primary key ที่ประกอบด้วยหลาย columns — เช่น PRIMARY KEY (user_id, currency) สำหรับ wallets table ที่แต่ละ user มี 1 wallet ต่อ currency

Junction Tables

ใช้แก้ many-to-many relationship — สร้าง table กลางที่มี foreign keys ไปยังทั้ง 2 tables เช่น user_roles (user_id, role_id)

Constraints (CHECK, UNIQUE)

  • CHECK (balance >= 0) — enforce business rules ที่ database level
  • UNIQUE (user_id, currency) — ป้องกัน duplicate records
  • Constraints เป็น safety net สุดท้าย ถึง application layer พลาดก็ไม่เข้า DB

Soft Delete Pattern

ใช้ deleted_at TIMESTAMPTZ แทนการ DELETE จริง — ข้อมูลยัง query ได้ (audit), กู้คืนง่าย ต้อง filter WHERE deleted_at IS NULL ในทุก query (หรือใช้ view)

Partitioning Strategies

แบ่ง table ใหญ่ออกเป็น partitions เพื่อ performance:

  • Range — แบ่งตาม date (เช่น monthly partitions สำหรับ transactions)
  • List — แบ่งตาม category/status
  • Hash — กระจาย rows สม่ำเสมอ

Audit Trail Design

ทุก data change ต้อง track ได้ — สร้าง audit table ที่บันทึก who, what, when, before/after values ใช้ triggers หรือ application-level logging สำหรับ financial data ห้ามลบ audit records

Multi-tenancy Patterns

  • Shared database, shared schema — ใช้ tenant_id column ทุก table + Row Level Security
  • Shared database, separate schema — แต่ละ tenant มี schema ของตัวเอง
  • Separate database — isolation สูงสุด แต่ manage ยาก

Schema Migration Strategies (Zero-downtime)

  • Add column ก่อน (nullable), deploy code ที่ write ค่าใหม่, backfill, แล้วค่อย add NOT NULL
  • ใช้ CREATE INDEX CONCURRENTLY เพื่อไม่ lock table
  • แยก migration เป็นหลาย steps เล็กๆ แทน 1 migration ใหญ่

UUID vs Auto-increment Trade-offs

  • UUID — globally unique, ไม่ต้อง coordinate ระหว่าง servers, ไม่เดาได้ แต่ larger, random → B-tree fragmentation
  • Auto-increment — compact, sequential → index-friendly แต่ need coordination, predictable
  • UUIDv7 (time-sortable) เป็น compromise ที่ดี

Event Sourcing vs CRUD

  • CRUD — store current state, update in-place — simple, familiar
  • Event Sourcing — store events (immutable log), derive current state — full audit trail, temporal queries แต่ complexity สูงกว่า

CQRS Pattern

Command Query Responsibility Segregation — แยก write model (normalized, consistent) ออกจาก read model (denormalized, optimized for queries) ใช้เมื่อ read/write patterns ต่างกันมาก

Related Skills

  • SQL — query language ที่ใช้กับ schema ที่ออกแบบ
  • PostgreSQL — database engine ที่ implement schema
  • Go — backend ที่ใช้ repository pattern เข้าถึง database