Bài này khác các bài còn lại — không dạy 1 tính năng SQL cụ thể, mà chuẩn bị môi trường thực hành thứ 2 dùng xuyên suốt 4 bài sau (9, 11, 15, 16, đánh dấu 🐳): 1 PostgreSQL thật chạy qua Docker trên máy bạn. 13/17 bài còn lại hoàn toàn không cần bước này — SQL workbench trong trình duyệt ở Bài 1 vẫn là "xương sống" chính của cả series.

1. Vì Sao Cần 2 Môi Trường Song Song?

SQLite-WASM chạy trong trình duyệt là 1 tiến trình đơn, 1 kết nối đơn — hoàn hảo để học cú pháp, cấu trúc dữ liệu, và logic truy vấn mà không cần cài đặt gì. Nhưng có những khái niệm về bản chất cần nhiều tiến trình/kết nối tranh chấp nhau thật sự mới quan sát được:

Khái niệm Vì sao browser không demo nổi Bài học liên quan
Isolation level & lock contention Cần ít nhất 2 kết nối riêng biệt tranh chấp cùng 1 dòng dữ liệu cùng lúc Bài 11
Query optimizer với thống kê thật Optimizer của PostgreSQL dùng model chi phí khác hẳn SQLite, cần dữ liệu đủ lớn + ANALYZE thật để thấy quyết định thực tế Bài 9
Disk I/O & fsync thật Trình duyệt không cho code JS truy cập trực tiếp đĩa cứng vật lý để đo độ trễ ghi thật Bài 15
WAL reader/writer đồng thời Cần 2 tiến trình hệ điều hành riêng biệt cùng mở 1 file .sqlite lúc này Bài 16
ℹ️ Docker là tuỳ chọn — không bắt buộc để học 13/17 bài còn lại
Nếu bạn chỉ quan tâm cú pháp SQL và cách tư duy dữ liệu quan hệ, có thể bỏ qua hoàn toàn phần Docker và chỉ theo dõi demo trình duyệt — vẫn đầy đủ 13/17 bài. Phần setup dưới đây chỉ cần thiết nếu bạn muốn tự tay quan sát 4 khái niệm ở bảng trên bằng 1 database server thật.

2. Dựng PostgreSQL Bằng Docker (Làm 1 Lần, Dùng Cho Cả Series)

Cách nhanh nhất — 1 lệnh docker run duy nhất, không cần file cấu hình:

docker run --name techmart-pg \
  -e POSTGRES_PASSWORD=techmart123 \
  -p 5432:5432 \
  -d postgres:16

Hoặc dùng docker-compose.yml nếu muốn cấu hình bền vững hơn (volume lưu dữ liệu giữa các lần khởi động lại):

version: "3.9"
services:
  db:
    image: postgres:16
    container_name: techmart-pg
    environment:
      POSTGRES_PASSWORD: techmart123
      POSTGRES_DB: techmart
    ports:
      - "5432:5432"
    volumes:
      - techmart-pg-data:/var/lib/postgresql/data

volumes:
  techmart-pg-data:
docker compose up -d

Kiểm tra kết nối và nạp dữ liệu TechMart (bản PostgreSQL, khai báo kiểu đúng chuẩn dialect):

psql -h localhost -U postgres -d techmart -c "SELECT version();"
psql -h localhost -U postgres -d techmart -f sql-techmart-postgres-seed.sql
🕳️ Cạm bẫy thường gặp: cổng 5432 đã bị chiếm
Nếu máy bạn đã cài PostgreSQL cục bộ (qua Homebrew, apt, hay 1 container khác), cổng 5432 có thể đã bị chiếm, khiến docker run báo lỗi bind: address already in use. Đổi cổng map bên ngoài, ví dụ -p 5433:5432, rồi kết nối qua psql -h localhost -p 5433 ....

⬇ Tải file seed TechMart cho PostgreSQL (.sql)

3. Cài sqlite3 CLI (Dùng Ở Bài 10 & 16)

Công cụ dòng lệnh chính thức để mở trực tiếp file .sqlite — dùng khi Bài 10 đọc hex thật của file, hoặc Bài 16 quan sát file -wal/-shm sinh ra trên đĩa. macOS/hầu hết bản Linux đã cài sẵn; nếu chưa có:

# macOS (Homebrew)
brew install sqlite3

# Debian/Ubuntu
sudo apt-get install sqlite3

# Kiểm tra
sqlite3 --version

4. Bản Đồ Khác Biệt Dialect: SQLite ↔ PostgreSQL

Đây là phần quan trọng nhất bài — SQLite và PostgreSQL giống nhau ở phần lớn cú pháp SELECT/JOIN/WHERE cơ bản (đó là lý do bạn có thể học SQL qua SQLite rồi áp dụng gần như nguyên vẹn sang PostgreSQL), nhưng khác nhau ở 1 số điểm cụ thể dễ gây lỗi khi chuyển đổi qua lại. Bấm từng mục để so sánh cú pháp 2 bên trên đúng bối cảnh TechMart:

🔄 Sân chơi tương tác: Dialect Translator

SQLite (dùng trong workbench trình duyệt)

PostgreSQL (dùng trong lab Docker)

sql-docker-lab-setup.js
🔬 Đào sâu: SERIAL thực chất là "đường tắt cú pháp", không phải kiểu dữ liệu thật
Khai báo product_id SERIAL trong PostgreSQL thực ra được engine "dịch ngầm" thành: tạo 1 SEQUENCE riêng, đặt cột kiểu INTEGER, và gán DEFAULT nextval('tên_sequence'). Đây là lý do khi INSERT thủ công kèm ID cụ thể (như file seed TechMart làm), sequence không tự biết ID lớn nhất đã dùng — phải gọi setval() đồng bộ lại, nếu không lần INSERT tiếp theo không chỉ định ID sẽ cố dùng lại ID đã tồn tại và báo lỗi trùng khoá chính.
💡 Mẹo: \d tên_bảng trong psql = .schema tên_bảng trong sqlite3
Cả 2 CLI đều có lệnh riêng xem nhanh cấu trúc 1 bảng mà không cần query information_schema/sqlite_master thủ công: psql dùng \d products, sqlite3 dùng .schema products (hoặc .tables để liệt kê mọi bảng).

Trắc nghiệm ôn tập

Câu 1: Vì sao cần Docker PostgreSQL thay vì chỉ dùng demo trình duyệt cho MỌI khái niệm trong series?

Trắc nghiệm ôn tập

Câu 2: SERIAL trong PostgreSQL thực chất hoạt động như thế nào phía dưới?

Trắc nghiệm ôn tập

Câu 3: Cú pháp FETCH FIRST 5 ROWS ONLY có chạy được trên SQLite không?

Trắc nghiệm ôn tập

Câu 4: Vì sao chỉ 4/17 bài trong series có lab Docker, còn lại thuần trình duyệt?

📖 Tài liệu tham khảo / References

Bài viết liên quan trong series

Bài 3: JOIN Toàn Tập Bài 1: Mô Hình Quan Hệ & SELECT Quay lại Lộ trình Series SQL