Relational model — vì sao Codd thắng IBM IMS năm 1970
Tuple, relation, attribute, set theory. 6 thuộc tính của relation + Codd's 12 rules. Vì sao mọi DB hiện đại từ Postgres đến Spanner đều build trên ý tưởng 1 paper 11 trang.
Năm 1970, IBM lưu dữ liệu dưới dạng cây phân cấp trong hệ thống IMS (Information Management System). Để trả lời câu hỏi "tên khách hàng của đơn hàng #5 là gì?", lập trình viên phải viết code navigation thủ công: đi tới node cha, duyệt con trỏ pointer, xuống node con, tìm đúng bản ghi — 4 bước navigation, gắn chặt với cấu trúc vật lý trên disk. Thay đổi cách lưu trữ đồng nghĩa với viết lại mọi query. Edgar Codd, một nhà toán học tại IBM San Jose, công bố một paper 11 trang tuyên bố: "data nên là quan hệ toán học, không phải cây." IBM bỏ qua ông.
10 năm sau, Larry Ellison dùng chính paper đó để xây Oracle — và bán license relational database ra thị trường. Hôm nay năm 2026, mọi major database (PostgreSQL, MySQL, Google Spanner, CockroachDB, Amazon Aurora) đều dựa trên ý tưởng trong 11 trang đó. Bài này giải thích ý tưởng cốt lõi đó là gì, vì sao nó thắng mô hình cây, và 2 quy tắc nền tảng mà mọi hệ thống relational đều phải tuân theo.
1. Analogy — Bảng Excel chặt chẽ hơn bạn nghĩ
Excel và relation trông giống nhau: cả hai đều có hàng và cột. Nhưng relation có thêm 6 ràng buộc toán học mà Excel không enforce — và chính những ràng buộc đó làm cho database query được một cách đáng tin cậy.
| Khái niệm Excel | Relational equivalent |
|---|---|
| File (workbook) | Database |
| Sheet (bảng tính) | Relation (table) |
| Hàng (row) | Tuple |
| Cột (column) | Attribute |
| Tên cột | Attribute name |
| Kiểu dữ liệu cột (text/number/date) | Domain |
| Khác Excel: thứ tự hàng | KHÔNG quan trọng — set semantics |
| Khác Excel: hàng trùng nhau | KHÔNG tồn tại — tuple uniqueness |
Relation = bảng Excel + 6 ràng buộc toán học. Excel là công cụ trình bày; relation là cấu trúc dữ liệu với ngữ nghĩa toán học.
2. Vì sao IMS thua — navigate vs declare
Để thấy rõ sự khác biệt, hãy xem hai cách trả lời câu hỏi "tên customer của order #5":
IMS — hierarchical navigation (4 bước thủ công):
// IMS pseudo-code (not real SQL)
// Step 1: open segment ORDERS
GU ORDERS (ORDER_ID = 5)
// Step 2: follow parent pointer to CUSTOMERS segment
GNP CUSTOMERS
// Step 3: read NAME field
name = current_segment.NAME
// Step 4: close cursor, handle not-found manually
Relational — declarative (1 câu):
-- 1 query, planner tu quyet dinh cach navigation
SELECT c.name
FROM customers c
JOIN orders o ON o.customer_id = c.id
WHERE o.id = 5;
Sự khác biệt không chỉ là độ dài code. Với IMS, nếu bạn thay đổi cách lưu trữ (di chuyển CUSTOMERS từ node cha sang bảng riêng), bạn phải sửa mọi navigation code. Với relational model, query không biết — và không cần biết — data được lưu thế nào trên disk. Database engine tự chọn cách thực thi hiệu quả nhất. Codd gọi đây là data independence — tách biệt logical structure (quan hệ toán học) khỏi physical storage.
IMS và relational đều lưu được data. Điểm khác biệt: khi DBA thêm index hay thay đổi cách partition data trong relational DB, các query đang chạy không cần sửa. Với IMS, mọi thay đổi storage format phá vỡ code navigation. Data independence là lý do relational DB scale được qua nhiều thập kỷ mà application code không phải rewrite.
3. 6 thuộc tính của relation
Relation không phải là "bảng bất kỳ". Một relation hợp lệ phải thỏa mãn đồng thời 6 thuộc tính sau:
1. Tuple uniqueness — không tồn tại 2 tuple hoàn toàn giống nhau trong cùng một relation. Database dùng set semantics: một tập hợp không có phần tử trùng.
-- Vi pham: insert 2 row giong het nhau (neu khong co UNIQUE constraint)
-- SQL cho phep lam dieu nay trong practice -- xem Pitfall section
INSERT INTO products (name, price) VALUES ('pen', 5000);
INSERT INTO products (name, price) VALUES ('pen', 5000); -- duplicate!
-- Theory noi: 2 tuple nay la 1. Practice SQL: can them PRIMARY KEY hoac UNIQUE.
2. No tuple ordering — relation là tập hợp (set), không phải danh sách (list). Thứ tự các tuple không có ý nghĩa toán học. SELECT * FROM users không guarantee thứ tự trả về.
-- SAI: gia dinh SELECT luon return theo thu tu insert
SELECT * FROM users; -- thu tu co the khac nhau moi lan chay
-- DUNG: luon them ORDER BY khi can thu tu cu the
SELECT * FROM users ORDER BY created_at DESC;
3. Atomic value — mỗi cell chứa đúng 1 giá trị scalar, không phải list, array, hay nested object. Đây là nền tảng của First Normal Form (1NF), sẽ đi sâu trong Module 4.
-- Vi pham atomic value (1NF violation)
-- tags chua list, khong phai 1 gia tri don
INSERT INTO tasks (title, tags) VALUES ('Fix login', 'bug,urgent,backend');
-- Dung: tach thanh bang rieng
CREATE TABLE task_tags (task_id INT, tag TEXT);
4. Named attribute — mỗi attribute (column) phải có tên duy nhất trong relation. Không thể có 2 column tên price trong cùng 1 bảng.
-- Invalid: 2 column cung ten (database tu choi)
CREATE TABLE orders (
id SERIAL,
price INT,
price INT -- ERROR: column "price" specified more than once
);
5. Same domain — mọi value trong 1 column phải thuộc cùng domain (kiểu dữ liệu). Column price INT không thể chứa string 'N/A'.
-- Database enforce domain qua type constraint
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
price INT CHECK (price > 0) -- domain: integer duong
);
6. No attribute ordering — thứ tự các column trong relation cũng không có ý nghĩa toán học. SELECT a, b và SELECT b, a chỉ khác về presentation, không khác về data.
4. Set theory dưới relation
Hiểu set theory giúp giải thích tại sao SQL có UNION, INTERSECT, và EXCEPT — và tại sao chúng hoạt động đúng như bạn kỳ vọng.
Cho 2 domain:
- Domain A:
{1, 2}(giá trị có thể của columnid) - Domain B:
{'a', 'b'}(giá trị có thể của columncode)
Cartesian product A × B cho ra tất cả tổ hợp có thể:
A x B = { (1, 'a'), (1, 'b'), (2, 'a'), (2, 'b') } -- 4 tuple
Một relation trên 2 domain này là bất kỳ subset nào của Cartesian product đó:
-- Relation hop le (subset cua A x B):
{ (1, 'a'), (2, 'b') }
-- Relation khac cung hop le:
{ (1, 'a'), (1, 'b'), (2, 'a') }
-- Empty relation cung hop le:
{ }
Chính vì relation là tập hợp (set) mà SQL có thể dùng set operations:
-- UNION: hop cua 2 tap hop (loai bo duplicate)
SELECT id FROM table_a
UNION
SELECT id FROM table_b;
-- INTERSECT: giao cua 2 tap hop
SELECT id FROM table_a
INTERSECT
SELECT id FROM table_b;
-- EXCEPT: hieu cua 2 tap hop (A tru B)
SELECT id FROM table_a
EXCEPT
SELECT id FROM table_b;
5. Codd's 12 rules — 2 cái thực sự quan trọng
Năm 1985, Codd publish thêm "Codd's 12 rules" để định nghĩa thế nào là một hệ thống "thực sự relational". Không cần học thuộc cả 12, nhưng 2 rule nền tảng sau là bắt buộc phải hiểu:
Rule 1 — Information rule: tất cả data trong database phải được biểu diễn dưới dạng relation (table), bao gồm cả metadata. Không có "hidden state" nào nằm ngoài table. Đây là lý do information_schema trong PostgreSQL cũng là bảng — bạn có thể query SELECT * FROM information_schema.tables để xem danh sách bảng, không cần lệnh đặc biệt.
-- Metadata cung la relation, query duoc binh thuong
SELECT table_name, table_type
FROM information_schema.tables
WHERE table_schema = 'public';
Rule 2 — Guaranteed access rule: mỗi giá trị atomic trong database phải accessible được bằng đúng bộ 3: (table_name, primary_key_value, column_name). Đây là lý do relational DB bắt buộc mỗi table phải có cơ chế xác định duy nhất từng row — thường là PRIMARY KEY.
-- Rule 2 in action: moi gia tri co the loc den bang (table, pk, column)
SELECT name -- column_name
FROM customers -- table_name
WHERE id = 42; -- primary_key_value
10 rules còn lại (tóm tắt 1 dòng mỗi cái):
- Rule 3: Null values — xử lý giá trị thiếu nhất quán (null không phải blank/zero)
- Rule 4: Dynamic online catalog — metadata query bằng cùng ngôn ngữ (SQL)
- Rule 5: Comprehensive data sublanguage — phải có 1 ngôn ngữ đầy đủ (SQL)
- Rule 6: View updating — view có thể update được khi điều kiện đủ đơn giản
- Rule 7: High-level insert/update/delete — thao tác set-based, không phải row-by-row
- Rule 8: Physical data independence — thay đổi storage không ảnh hưởng query
- Rule 9: Logical data independence — thay đổi logical schema tối thiểu ảnh hưởng app
- Rule 10: Integrity independence — constraints định nghĩa trong DB, không trong app
- Rule 11: Distribution independence — query không đổi dù data phân tán hay tập trung
- Rule 12: Non-subversion rule — không có "back door" bypass relational integrity
PostgreSQL comply khoảng 9-10/12 rules — thuộc hàng tốt nhất trong các commercial và open-source RDBMS. MySQL comply khoảng 7-8/12. Không có hệ thống nào đạt 12/12 — Rule 6 (view updating) và Rule 9 (logical data independence) thực tế rất khó đạt đầy đủ. Nhưng 2 rule nền tảng (Rule 1 + Rule 2) thì PostgreSQL enforce hoàn toàn.
6. Pitfall — nhầm relation với Excel hoặc CSV
Nhiều bug production xuất phát từ giả định "SELECT luôn trả về theo thứ tự insert". Đây là sai lầm phổ biến nhất khi mới học SQL. Relation là set — không có thứ tự. Khi không có ORDER BY, database engine tự do chọn bất kỳ thứ tự nào hiệu quả nhất tại thời điểm đó (hash join output, parallel scan merge, index scan order). Query chạy đúng trong development, sai trong production vì execution plan khác nhau.
Pitfall 1 — giả định row order:
-- SAI: lay "row moi nhat" ma khong ORDER BY
-- Ket qua co the khac nhau moi lan chay, moi version Postgres
SELECT * FROM events LIMIT 1;
-- DUNG: chi dinh ro rang thu tu
SELECT * FROM events ORDER BY created_at DESC LIMIT 1;
Pitfall 2 — SQL cho phép duplicate row khi thiếu UNIQUE constraint:
Về mặt lý thuyết, relation không có duplicate tuple. Nhưng SQL thực tế cho phép insert duplicate nếu bảng không có UNIQUE hoặc PRIMARY KEY constraint — đây là compromise giữa relational theory và practical performance. Hệ quả: một bảng SQL không có PK có thể vi phạm set semantics.
-- Tao bang khong co PRIMARY KEY (bad practice)
CREATE TABLE log_entries (
event_type TEXT,
occurred_at TIMESTAMPTZ
);
-- Insert duplicate: SQL cho phep
INSERT INTO log_entries VALUES ('login', '2024-01-01 10:00:00');
INSERT INTO log_entries VALUES ('login', '2024-01-01 10:00:00');
-- Bay gio co 2 row giong het -- vi pham tuple uniqueness theory
-- Can dung DISTINCT de dedup, hoac them PRIMARY KEY ngay tu dau
SELECT DISTINCT event_type, occurred_at FROM log_entries;
Best practice: luôn định nghĩa PRIMARY KEY cho mọi table. Không chỉ vì Codd Rule 2, mà còn vì không có PK thì DELETE cụ thể một row cũng khó.
7. Applied — vì sao SQL portable cross-vendor
Vì mọi vendor đều implement relational model + ANSI SQL standard, query cơ bản chạy được trên nhiều engine khác nhau:
-- Query nay chay duoc tren PostgreSQL, MySQL, SQLite, MSSQL, Oracle
SELECT p.name, p.price
FROM products p
WHERE p.price > 100
ORDER BY p.price ASC;
Thử với e-commerce catalog 50.000 sản phẩm — cùng 1 câu query trên, chạy trên 4 engine khác nhau, đều trả về đúng kết quả. Lý do: cả 4 engine đều build trên relational model (tuple, attribute, domain, set semantics) và đều support ANSI SQL core.
Đây là lý do bài M01.6 về SQL flavor map chỉ cần liệt kê chỗ khác nhau giữa các vendor — vì phần giống nhau chiếm khoảng 90% và xuất phát từ cùng nền tảng relational model.
SQL có chuẩn ISO/IEC 9075, cập nhật theo các phiên bản SQL:1992, SQL:1999, SQL:2003, SQL:2011, SQL:2016, SQL:2023. Các vendor đều implement một subset của chuẩn này. Phần core (SELECT/FROM/WHERE/JOIN/GROUP BY/ORDER BY) gần như đồng nhất. Phần khác biệt: window functions syntax, JSON support, full-text search, stored procedure language, và type system details.
8. Deep Dive — Relational foundations
- Codd 1970 — "A Relational Model of Data for Large Shared Data Banks" (PDF free) — Paper gốc 11 trang. Đọc Section 1-3 (khoảng 10 trang) để hiểu ý tưởng cốt lõi: tại sao Codd chọn set theory, định nghĩa relation/tuple/domain, và data independence. Không cần đọc phần derivability và redundancy ở cuối trong lần đầu.
- Readings in Database Systems "Red Book" 5th ed — Ch.1 Background — Hellerstein's commentary giải thích bối cảnh lịch sử: vì sao IMS thất bại, vì sao Codd paper thay đổi ngành, và vì sao relational model vẫn dominant sau 50 năm. Đọc free online, khoảng 15 phút.
- Database System Concepts (Silberschatz/Korth/Sudarshan, 7th ed) — Ch.2 "Introduction to the Relational Model" — Textbook treatment với formal definition + practice problems. Phần 2.1-2.3 cho relational structure, phần 2.4-2.6 cho relational algebra (nền tảng của SQL optimizer). Đọc sau khi đã xong M02 (SELECT) để thấy relational algebra map lên SQL query như thế nào.
Ghi chú: Đọc theo thứ tự: Codd paper trước để có intuition trực tiếp từ nguồn gốc, Red Book commentary để có context lịch sử và "aha moment", sau đó Database System Concepts Ch.2 để có rigor toán học với practice problems.
Liên kết khoá học khác
- Khoá Spring — bài 4.2 Entity Mapping — JPA
@Entitymap relational model thành Java class thế nào.
9. Tóm tắt
- Relation là tập hợp (set) các tuple, mỗi tuple có cùng tập attribute — không phải bảng Excel tùy tiện mà là cấu trúc toán học với 6 ràng buộc chặt chẽ.
- 6 thuộc tính cốt lõi: tuple uniqueness, no tuple ordering, atomic value, named attribute, same domain, no attribute ordering — cả 6 cùng nhau tạo ra set semantics.
- Set semantics quan trọng vì nó cho phép query optimizer tự do reorder operations (hash join, parallel scan, merge join) mà không thay đổi kết quả — nền tảng của query optimization.
- Codd Rule 1 (Information rule): mọi data là relation, kể cả metadata — không có hidden state ngoài bảng.
- Codd Rule 2 (Guaranteed access): mọi giá trị accessible qua
(table, primary_key, column)— lý do PRIMARY KEY là bắt buộc. - Mọi major RDBMS build trên cùng nền tảng relational model + ANSI SQL, nên query core portable cross-vendor — vendor khác nhau ở phần extension, không phải phần nền tảng.
- Bài tiếp theo M02 (SELECT) xây trực tiếp trên set semantics: mỗi SELECT trả về 1 relation mới. M04 (Normalization) giải thích tại sao atomic value (thuộc tính #3) dẫn đến 1NF và các normal form cao hơn.
10. Tự kiểm tra
Q1Vì sao "no tuple ordering" trong relation lại quan trọng cho query optimization? Nếu relation có thứ tự cố định, điều gì sẽ xảy ra?▸
Khi relation không có thứ tự, query planner được tự do chọn bất kỳ thuật toán thực thi nào hiệu quả nhất. Hash join không cần preserve thứ tự input; sort-merge join có thể xử lý 2 stream song song; parallel scan có thể chia data cho nhiều thread rồi merge kết quả không cần quan tâm thứ tự từng phần. Tất cả những chiến lược này tạo ra kết quả theo thứ tự tùy ý — và điều đó hoàn toàn hợp lệ vì output cũng là relation (set).
Nếu relation có thứ tự cố định (như list), optimizer sẽ bị ràng buộc phải preserve thứ tự qua mọi intermediate step — mỗi join, mỗi aggregation, mỗi filter đều phải cẩn thận không xáo trộn thứ tự. Chi phí đó lớn đến mức làm mất đi phần lớn lợi thế của declarative query. Đây chính xác là vấn đề của IMS: navigation thủ công theo cấu trúc vật lý, không thể optimize.
Hệ quả thực tế: khi bạn không thêm ORDER BY, database không "lười" — nó đang exploit set semantics để chạy nhanh hơn.
Q2Phân biệt "no duplicate tuple" trong relational theory vs SQL thực tế — vì sao SQL cho phép insert duplicate khi không có UNIQUE constraint?▸
Relational theory (Codd 1970) dùng set semantics: tập hợp không có phần tử trùng. Về mặt toán học, 2 tuple giống hệt nhau là 1 phần tử — không thể tồn tại 2 bản copy trong cùng 1 relation.
SQL thực tế chọn bag semantics (multiset) làm default: SQL table có thể chứa duplicate row nếu không có PRIMARY KEY hoặc UNIQUE constraint. Đây là quyết định thiết kế có chủ ý từ SQL:1992 vì 2 lý do: (1) enforce uniqueness tự động trên toàn bộ row rất tốn kém — phải hash hoặc sort toàn bộ row để check; (2) nhiều use case (log table, event stream) cần duplicate row có chủ đích.
Hệ quả thực tế: bảng không có PK vi phạm relational theory nhưng SQL engine vẫn cho phép. Best practice là luôn định nghĩa PRIMARY KEY — không chỉ để đúng theory, mà còn vì không có PK thì DELETE cụ thể 1 row trong số các row duplicate là không thể trong standard SQL.
Q3Bạn có table users(id, name, hobbies TEXT) với hobbies = 'đọc sách,xem phim'. Vi phạm thuộc tính nào của relation? Hậu quả gì khi query?▸
Vi phạm thuộc tính atomic value (thuộc tính #3) — mỗi cell phải chứa 1 giá trị scalar, không phải list hay comma-separated string. Đây cũng là vi phạm First Normal Form (1NF), sẽ học chi tiết trong Module 4.
Hậu quả cụ thể khi query:
- Không thể filter hiệu quả:
WHERE hobbies = 'đọc sách'không tìm được user có hobby đọc sách vì value là chuỗi kết hợp, không phải giá trị đơn. Phải dùngWHERE hobbies LIKE '%đọc sách%'— không dùng index được, full scan. - Không thể JOIN: không thể join với bảng
hobbiesmaster list vì không có atomic foreign key. - Thống kê sai:
COUNT(*) GROUP BY hobbiessẽ group theo toàn bộ chuỗi, không phải từng hobby riêng lẻ.
Fix đúng: tách thành bảng user_hobbies(user_id, hobby) với 1 row mỗi hobby — mỗi cell atomic, query bằng JOIN bình thường.
Q4Codd Rule 2 (Guaranteed access) bị vi phạm khi nào trong production system? Cho ví dụ cụ thể và hậu quả.▸
Guaranteed access rule nói rằng mọi giá trị phải accessible bằng bộ 3 (table_name, primary_key, column_name). Rule này bị vi phạm khi database không thể xác định duy nhất một row — tức là thiếu primary key hoặc có duplicate key.
Ví dụ vi phạm thực tế:
- Table không có PK: bảng
event_logs(user_id, action, timestamp)không có PK. Nếu cùng user thực hiện cùng action trong cùng timestamp (hiếm nhưng xảy ra), không có cách nào truy cập uniquely 1 trong 2 row đó — rule 2 vi phạm. - Hidden state ngoài DB: ứng dụng lưu session state trong Redis hoặc in-memory cache thay vì DB — data tồn tại nhưng không accessible qua relational interface, không query được bằng SQL.
- Surrogate key là SERIAL nhưng bị reset: sau khi truncate + reinsert, cùng surrogate key có thể map sang entity khác — guaranteed access theo key sai.
Hậu quả: audit trail không complete, debug khó vì không thể query exact state, và application code phải biết về "hidden channels" để đọc đủ data — phá vỡ data independence.
Q5Vì sao PostgreSQL không cần 100% comply Codd's 12 rules vẫn được gọi là "relational database"? Đâu là ranh giới tối thiểu?▸
Codd's 12 rules là ideal specification, không phải binary test. Codd tự biết khi viết chúng rằng không hệ thống nào đạt 12/12 — ông publish chúng như tiêu chí đánh giá và marketing checklist để chống lại vendor gắn nhãn sai "relational" cho sản phẩm hierarchical hoặc network model.
Ranh giới tối thiểu thực tế là Rule 1 và Rule 2: toàn bộ data là relation (không có hidden state), và mọi giá trị accessible qua primary key. Nếu 2 rule này đứng vững, hệ thống có đủ nền tảng toán học để được gọi là relational.
Các rule khó comply nhất là Rule 6 (view updating — view phức tạp không thể update được vì ambiguous mapping back to base tables) và Rule 9 (logical data independence — thay đổi schema mà không ảnh hưởng app trong thực tế luôn có một số trường hợp ngoại lệ). PostgreSQL chọn practical compliance: implement phần có thể implement clean, document rõ phần nào không support và tại sao — thay vì fake compliance để đạt số cao hơn.
Bài tiếp theo: ER modeling — bản vẽ trước khi gõ DDL
Bài này có giúp bạn hiểu bản chất không?