Mô hình Quan hệ & SQL: Tổ chức dữ liệu của thế giới
Bài báo năm 1970 của Edgar Codd đã cho chúng ta nền tảng toán học cho cơ sở dữ liệu, và SQL cho chúng ta một ngôn ngữ để truy vấn chúng. IBM ngồi trên nó. Oracle xuất xưởng nó trước.
TL;DR
Năm 1970, một nhà toán học tại IBM tên Edgar Codd đã xuất bản một bài báo định nghĩa lại cách con người lưu trữ và truy xuất dữ liệu. Trước Codd, cơ sở dữ liệu là những mê cung — bạn phải biết bố cục vật lý của dữ liệu để tìm bất cứ thứ gì. Codd nói: tách cái gì khỏi như thế nào. Tổ chức dữ liệu như các quan hệ toán học (bảng), truy vấn bằng logic, và để máy tính tính toán các chi tiết vật lý. IBM hiểu rằng điều đó xuất sắc và dành nhiều năm không xuất xưởng nó. Oracle đọc chính các bài báo nghiên cứu của IBM và đánh bại họ ra thị trường trước. Ngôn ngữ mà các đồng nghiệp của Codd phát minh để làm cho toán học của ông dễ tiếp cận — SQL — trở thành ngôn ngữ dữ liệu được sử dụng rộng rãi nhất trong lịch sử và vẫn vậy năm mươi năm sau.
Vấn đề mê cung
Trước năm 1970, cơ sở dữ liệu được xây dựng xoay quanh cách dữ liệu được lưu trữ, không phải dữ liệu có nghĩa gì.
Mô hình thống trị là phân cấp — IMS (Information Management System) của IBM, được sử dụng để theo dõi các linh kiện cho chương trình Apollo, tổ chức các bản ghi trong cây. Để tìm các linh kiện của một nhà cung cấp, bạn đi từ gốc, qua các phòng ban, qua các kho, xuống đến bản ghi bạn muốn. Đường đi được mã hóa cứng trong chương trình của bạn. Thay đổi cấu trúc lưu trữ, và mọi ứng dụng chạm vào nó đều hỏng.
Cơ sở dữ liệu mạng (tiêu chuẩn CODASYL) linh hoạt hơn một chút — các bản ghi có thể có nhiều cha — nhưng lập trình viên vẫn phải duyệt qua các con trỏ rõ ràng giữa các bản ghi. Bạn không hỏi cái gì bạn muốn. Bạn mô tả cách điều hướng đến nó.
Điều này tạo ra một vấn đề căn bản: phụ thuộc dữ liệu. Ứng dụng của bạn biết quá nhiều về bố cục vật lý của dữ liệu. Tái tổ chức lưu trữ — di chuyển một file, thêm một index — có thể yêu cầu viết lại hàng nghìn chương trình. Cơ sở dữ liệu đắt để xây và gần như không thể thay đổi.
Edgar Codd đã dành nhiều năm suy nghĩ về vấn đề này từ phía sai của tòa nhà tại Phòng Nghiên cứu IBM San Jose. Ông là nhà toán học, không phải kỹ sư, và ông cho rằng các kỹ sư đang giải sai vấn đề hoàn toàn.
Tuệ giác của Codd: Độc lập dữ liệu
Bài báo năm 1970 của Codd — “A Relational Model of Data for Large Shared Data Banks”, xuất bản trong Communications of the ACM — đưa ra một lập luận đơn giản một cách lừa dối:
Tổ chức dữ liệu dưới dạng quan hệ (bảng gồm các hàng và cột). Truy vấn nó bằng đại số quan hệ — các phép toán từ toán học mô tả cái gì bạn muốn, không phải cách truy xuất nó. Để một trình tối ưu truy vấn tìm ra đường truy cập vật lý.
Điều này cho ứng dụng độc lập dữ liệu: chương trình không cần biết liệu dữ liệu được lưu trên băng, có index, được phân mảnh, hay được tái tổ chức. Chúng chỉ mô tả điều chúng muốn. Công việc của engine cơ sở dữ liệu là tìm ra cách cung cấp nó.
Một quan hệ chỉ là một bảng: một tập các bộ (hàng), mỗi bộ tuân theo cùng schema (cột). Điều làm cho nó mạnh mẽ là các phép toán toán học bạn có thể áp dụng:
Bảng Orders: Bảng Customers:
┌────┬─────────┬──────┐ ┌────┬──────────────┬──────────┐
│ id │ cust_id │ amt │ │ id │ name │ city │
├────┼─────────┼──────┤ ├────┼──────────────┼──────────┤
│ 1 │ 101 │ 250 │ │101 │ Ada Lovelace │ London │
│ 2 │ 102 │ 80 │ │102 │ Alan Turing │ London │
│ 3 │ 101 │ 430 │ └────┴──────────────┴──────────┘
└────┴─────────┴──────┘
JOIN trên cust_id = id WHERE city = 'London':
→ Tất cả đơn hàng đặt bởi khách hàng London
Tuệ giác then chốt: phép join. Bằng cách diễn đạt các mối quan hệ qua các giá trị chia sẻ (khóa ngoại) thay vì con trỏ vật lý, dữ liệu có thể được kết hợp theo những cách mà các nhà thiết kế ban đầu chưa bao giờ lường trước. Bạn không phải dự đoán mọi truy vấn khi thiết kế schema — bạn chỉ phải mô hình hóa dữ liệu đúng, và đại số quan hệ sẽ xử lý phần còn lại.
Chuẩn hóa: Thiết kế dữ liệu không dư thừa
Codd cũng hình thức hóa chuẩn hóa — một tập các quy tắc để cấu trúc các bảng nhằm giảm thiểu dư thừa và ngăn ngừa mâu thuẫn.
Vấn đề cổ điển: lưu thành phố của khách hàng trong mỗi hàng đơn hàng, và bạn có một nghìn hàng để cập nhật khi họ chuyển nhà. Sai một cái, dữ liệu của bạn giờ mâu thuẫn. Lưu thành phố một lần trong bảng customers, tham chiếu nó theo ID, và chỉ có một chỗ để cập nhật.
Codd định nghĩa dạng chuẩn — các ràng buộc ngày càng nghiêm ngặt về thiết kế bảng:
-- Tệ: thành phố bị nhân bản trong mỗi hàng đơn hàng
CREATE TABLE orders_bad (
id INT,
cust_id INT,
cust_city TEXT, -- ← nhân bản, sẽ lỗi thời
amount DECIMAL
);
-- Tốt: thành phố sống một lần trong customers, được join khi cần
CREATE TABLE customers (
id INT PRIMARY KEY,
city TEXT
);
CREATE TABLE orders (
id INT PRIMARY KEY,
cust_id INT REFERENCES customers(id),
amount DECIMAL
);
Dạng chuẩn thứ nhất, thứ hai, và thứ ba (1NF, 2NF, 3NF) loại bỏ các dạng dư thừa ngày càng tinh vi. Hầu hết schema thực tế nhắm đến 3NF. Codd sau đó đã định nghĩa Dạng Chuẩn Boyce-Codd (BCNF) sau một cuộc trò chuyện với Don Chamberlin và Ray Boyce tiết lộ một khoảng trống trong 3NF.
SEQUEL: Làm cho toán học dễ đọc
Đại số quan hệ của Codd thanh lịch về mặt toán học và không sử dụng được trong thực tế cho bất kỳ ai không có bằng toán học. IBM giao cho hai nhà nghiên cứu — Don Chamberlin và Ray Boyce — biến nó thành thứ mà lập trình viên có thể đọc.
Chamberlin tham dự một trong các buổi nói chuyện của Codd và bước ra với sự chắc chắn:
“Tôi thấy Codd đang làm gì, và tôi nghĩ: Tôi có thể viết một ngôn ngữ mà bất cứ ai cũng có thể sử dụng.”
Họ gọi nó là SEQUEL — Structured English Query Language. Cái tên sau đó được rút ngắn thành SQL do xung đột thương hiệu với một công ty máy bay.
Mục tiêu thiết kế là dễ đọc như tiếng Anh. Thay vì ký hiệu đại số quan hệ, bạn sẽ viết thứ trông như một câu:
-- Đại số quan hệ (toán học của Codd trông như thế nào):
π name, city (σ city='London' (Customers))
-- SQL (thứ Chamberlin và Boyce đã thiết kế):
SELECT name, city
FROM customers
WHERE city = 'London';
-- Sức mạnh đầy đủ: join các bảng, tổng hợp, lọc
SELECT
c.name,
COUNT(o.id) AS order_count,
SUM(o.amount) AS total_spent
FROM customers c
JOIN orders o ON o.cust_id = c.id
WHERE c.city = 'London'
GROUP BY c.name
HAVING SUM(o.amount) > 200
ORDER BY total_spent DESC;
SQL mô tả cái gì cần truy xuất. Engine cơ sở dữ liệu quyết định như thế nào — index nào để sử dụng, thuật toán join nào, có quét toàn bảng hay tìm kiếm một hàng cụ thể. Sự tách biệt mối quan tâm này là cách mạng.
IBM ngồi trên nó. Oracle thì không.
IBM xây dựng System R (1974-1979), triển khai cơ sở dữ liệu quan hệ đầu tiên, như một dự án nghiên cứu. Nó chứng minh khái niệm hoạt động. IBM sau đó dành nhiều năm quyết định có sản phẩm hóa nó hay không, một phần vì IMS — cơ sở dữ liệu phân cấp hiện có của họ — đang sinh lời và được triển khai khắp nơi.
Larry Ellison đọc các bài báo System R đã xuất bản của IBM. Năm 1977, ông thành lập Software Development Laboratories — sau đổi tên thành Oracle — với một kế hoạch đơn giản: xây dựng thứ IBM mô tả trước khi IBM làm.
Oracle xuất xưởng cơ sở dữ liệu quan hệ thương mại đầu tiên vào năm 1979, một năm trước sản phẩm của chính IBM. IBM theo sau với SQL/DS năm 1981 và DB2 năm 1983. Đến lúc đó, Oracle đã có khoảng dẫn trước mà họ không bao giờ giao lại.
Bài học không bị ngành bỏ qua: xuất bản nghiên cứu là một hành động hào phóng với đối thủ cạnh tranh của bạn.
Đến năm 1983, cơ sở dữ liệu quan hệ đã thay thế cơ sở dữ liệu phân cấp như mặc định. Năm 1986, SQL trở thành một tiêu chuẩn ANSI. Hôm nay, mọi cơ sở dữ liệu lớn — PostgreSQL, MySQL, SQLite, SQL Server, BigQuery — đều nói một biến thể của ngôn ngữ mà hai nhà nghiên cứu IBM đã thiết kế để làm cho ý tưởng của một nhà toán học dễ tiếp cận.
ACID: Lời hứa của cơ sở dữ liệu
Khi cơ sở dữ liệu quan hệ đi vào sản xuất, các kỹ sư cần một đảm bảo: nếu mất điện giữa giao dịch, dữ liệu ở trạng thái nào?
ACID — được hình thức hóa năm 1983 bởi Theo Härder và Andreas Reuter — định nghĩa bốn tính chất mà một giao dịch cơ sở dữ liệu phải có:
- Tính nguyên tử (Atomicity) — một giao dịch hoàn thành đầy đủ hoặc không xảy ra gì. Không có đơn hàng nửa chừng.
- Tính nhất quán (Consistency) — mọi giao dịch để lại cơ sở dữ liệu ở trạng thái hợp lệ. Khóa ngoại được giữ. Các ràng buộc được tôn trọng.
- Cách ly (Isolation) — các giao dịch đồng thời không thấy trạng thái trung gian của nhau. Hai người dùng đặt chỗ cuối cùng có câu trả lời đúng.
- Tính bền vững (Durability) — một khi đã commit, giao dịch sống sót qua các vụ sập. Ghi đã ở đĩa, không chỉ trong bộ nhớ.
BEGIN;
UPDATE accounts SET balance = balance - 500 WHERE id = 1;
UPDATE accounts SET balance = balance + 500 WHERE id = 2;
COMMIT;
-- Cả hai cập nhật đều xảy ra, hoặc không cái nào. Không bao giờ chỉ một.
ACID là thứ tách biệt cơ sở dữ liệu khỏi file. Đó là lý do tại sao ngân hàng tin tưởng cơ sở dữ liệu quan hệ với tiền, bệnh viện tin tưởng chúng với hồ sơ, và các hãng hàng không tin tưởng chúng với kho ghế. Các đảm bảo khó triển khai — write-ahead log, kiểm soát đồng thời đa phiên bản, khóa hai pha — nhưng lập trình viên không thấy bất cứ điều nào trong số đó. Họ chỉ viết SQL và tin vào lời hứa.
Mô hình Quan hệ đã làm đúng gì
Bài báo năm 1970 của Codd là một trong những bài được trích dẫn nhiều nhất trong khoa học máy tính, và các ý tưởng đã tồn tại tốt hơn gần như bất cứ điều gì khác từ thời đại đó:
- Độc lập dữ liệu — đổi engine lưu trữ, thêm index, phân mảnh bảng — ứng dụng vẫn hoạt động
- Truy vấn khai báo — mô tả kết quả, không phải thuật toán; để trình tối ưu tìm đường tốt nhất
- Phép join — các mối quan hệ được diễn đạt qua giá trị, không phải con trỏ, làm cho dữ liệu có thể kết hợp theo những cách không ai dự đoán
- Các tiêu chuẩn mở — việc chuẩn hóa ANSI của SQL có nghĩa là kiến thức chuyển giao giữa các hệ thống
Mô hình quan hệ không hoàn hảo. Nó vật lộn với dữ liệu phân cấp (XML, JSON), các mối quan hệ đồ thị, và chuỗi thời gian ở quy mô lớn. NoSQL xuất hiện vào những năm 2000 một phần để thoát khỏi các ràng buộc của nó. Nhưng cơ sở dữ liệu NoSQL nhất quán thêm các giao diện SQL trở lại — vì SQL, hóa ra, không phải là ràng buộc. Nó là giải pháp.
Internet giờ chạy trên TCP/IP để giao tiếp và SQL cho dữ liệu. Cả hai đều được thiết kế vào đầu những năm 1970. Cả hai vẫn đang chạy.