A B-Tree is a self-balancing tree data structure that maintains sorted data and allows searches, insertions, and deletions in O(log n) time. Unlike binary trees, B-Trees can have many children per node, making them ideal for systems that read and write large blocks of data like databases and file systems.
B-Tree là cấu trúc dữ liệu cây tự cân bằng duy trì dữ liệu đã sắp xếp và cho phép tìm kiếm, chèn và xóa trong thời gian O(log n). Khác với cây nhị phân, B-Tree có thể có nhiều con mỗi nút, làm cho nó lý tưởng cho các hệ thống đọc và ghi khối dữ liệu lớn như cơ sở dữ liệu và hệ thống tập tin.
B-Tree giảm thiểu I/O đĩa bằng cách lưu nhiều khóa mỗi nút. Một lần đọc đĩa có thể lấy toàn bộ nút với hàng trăm khóa, giảm đáng kể số lần đọc cần thiết so với cây nhị phân.
| Operation | Average | Worst | Disk I/O |
|---|---|---|---|
| Search | O(log n) | O(log n) | O(log_m n) |
| Insert | O(log n) | O(log n) | O(log_m n) |
| Delete | O(log n) | O(log n) | O(log_m n) |
| Range Query | O(log n + k) | O(log n + k) | O(log_m n + k/m) |
| Space | O(n) - each key stored once | ||
n = number of keys, m = order (max children), k = number of results in range
A B-Tree of order m (maximum children per node) has specific rules that keep it balanced and efficient for disk-based storage.
B-Tree bậc m (số con tối đa mỗi nút) có các quy tắc cụ thể giữ cho nó cân bằng và hiệu quả cho lưu trữ dựa trên đĩa.
- Every node has at most m children
Mỗi nút có tối đa m con
- Every non-leaf node (except root) has at least ⌈m/2⌉ children
Mỗi nút không phải lá (trừ gốc) có ít nhất ⌈m/2⌉ con
- Root has at least 2 children if it is not a leaf
Gốc có ít nhất 2 con nếu không phải là lá
- All leaves appear at the same depth
Tất cả các lá xuất hiện ở cùng độ sâu
- A non-leaf node with k children contains k-1 keys
Nút không phải lá có k con chứa k-1 khóa
Searching in a B-Tree is similar to a binary search tree, but at each node you binary search among multiple keys to find which child to follow.
Tìm kiếm trong B-Tree tương tự như cây tìm kiếm nhị phân, nhưng ở mỗi nút bạn tìm nhị phân trong nhiều khóa để tìm con nào cần theo.
1function search(node: BTreeNode, key: number): Data | null {2 // Binary search within node's keys3 let i = 0;4 while (i < node.keys.length && key > node.keys[i]) {5 i++;6 }78 // Found exact match9 if (i < node.keys.length && key === node.keys[i]) {10 return node.data[i];11 }1213 // Reached a leaf without finding14 if (node.isLeaf) {15 return null;16 }1718 // Recurse into appropriate child19 return search(node.children[i], key);20}Insertion always happens at a leaf. If the leaf overflows (more than m-1 keys), it splits into two nodes and the middle key moves up to the parent. This split can cascade up to the root.
Chèn luôn xảy ra ở lá. Nếu lá tràn (nhiều hơn m-1 khóa), nó tách thành hai nút và khóa giữa di chuyển lên nút cha. Việc tách này có thể lan truyền lên đến gốc.
1function split(node: BTreeNode): { left: BTreeNode; mid: number; right: BTreeNode } {2 const midIndex = Math.floor(node.keys.length / 2);3 const midKey = node.keys[midIndex];45 const left = new BTreeNode();6 left.keys = node.keys.slice(0, midIndex);7 left.children = node.children.slice(0, midIndex + 1);89 const right = new BTreeNode();10 right.keys = node.keys.slice(midIndex + 1);11 right.children = node.children.slice(midIndex + 1);12Deletion is more complex. If deleting from a leaf causes underflow (fewer than ⌈m/2⌉-1 keys), the node must borrow from a sibling or merge with it.
Xóa phức tạp hơn. Nếu xóa từ lá gây thiếu (ít hơn ⌈m/2⌉-1 khóa), nút phải mượn từ anh em hoặc gộp với nó.
- Leaf with enough keys: simply remove
Lá có đủ khóa: chỉ cần xóa
- Leaf underflow + sibling has extra: borrow through parent
Lá thiếu + anh em có dư: mượn qua cha
- Leaf underflow + sibling minimal: merge with sibling and parent key
Lá thiếu + anh em tối thiểu: gộp với anh em và khóa cha
- Internal node: replace with predecessor/successor, then handle leaf
Nút trong: thay bằng tiền nhiệm/hậu nhiệm, sau đó xử lý lá
Khi hai nút gộp, nút cha mất một khóa. Điều này có thể làm cha thiếu, lan truyền việc sửa lên cây. Trong trường hợp xấu nhất, chiều cao cây giảm 1.
B+ Trees are a variant where all data is stored in leaves and internal nodes only contain keys for navigation. Leaves are linked for efficient range queries.
B+ Tree là biến thể trong đó tất cả dữ liệu được lưu ở lá và các nút trong chỉ chứa khóa để điều hướng. Các lá được liên kết để truy vấn khoảng hiệu quả.
- B-Tree: Data in all nodes | B+ Tree: Data only in leaves
B-Tree: Dữ liệu ở mọi nút | B+ Tree: Dữ liệu chỉ ở lá
- B-Tree: Fewer keys per level | B+ Tree: More keys (internal nodes smaller)
B-Tree: Ít khóa hơn mỗi tầng | B+ Tree: Nhiều khóa hơn (nút trong nhỏ hơn)
- B-Tree: No leaf links | B+ Tree: Leaves linked for range scans
B-Tree: Không liên kết lá | B+ Tree: Lá được liên kết cho quét khoảng
B-Trees are designed for systems where disk reads are expensive. By fitting hundreds of keys in each node, a B-Tree with millions of records may only be 3-4 levels deep.
B-Tree được thiết kế cho hệ thống nơi đọc đĩa tốn kém. Bằng cách chứa hàng trăm khóa trong mỗi nút, B-Tree với hàng triệu bản ghi có thể chỉ sâu 3-4 tầng.
With a B-Tree of order 500: each node holds up to 499 keys. With 1 million records, the tree only needs 3 levels. Each search requires only 3 disk reads instead of 20 with a binary tree.
Với B-Tree bậc 500: mỗi nút chứa tối đa 499 khóa. Với 1 triệu bản ghi, cây chỉ cần 3 tầng. Mỗi lần tìm kiếm chỉ cần 3 lần đọc đĩa thay vì 20 lần với cây nhị phân.
Hệ thống cơ sở dữ liệu thường định kích thước nút B-Tree khớp với kích thước khối đĩa (4KB-16KB). Điều này đảm bảo mỗi lần đọc đĩa lấy chính xác một nút hoàn chỉnh, tối đa hóa hiệu quả.
- Choosing too small an order: Tree becomes deeper, more disk I/O
Chọn bậc quá nhỏ: Cây sâu hơn, nhiều I/O đĩa hơn
- Choosing too large an order: Binary search within node slows down, wastes space
Chọn bậc quá lớn: Tìm nhị phân trong nút chậm, lãng phí không gian
- Forgetting cascading splits: Node splits can propagate to root
Quên xử lý tách lan truyền: Tách nút có thể lan đến gốc
- Forgetting cascading merges: Merges during deletion can also propagate up
Quên xử lý gộp lan truyền: Gộp nút khi xóa cũng có thể lan lên
- Not considering B+ Tree for range queries: B+ Tree is better for range scans
Không cân nhắc B+ Tree cho truy vấn khoảng: B+ Tree tốt hơn cho range queries
- Ignoring caching: Root and frequently accessed nodes should be cached
Bỏ qua bộ đệm: Nút gốc và các nút phổ biến nên được cache
- Optimized for disk-based storage with large block I/O
Tối ưu cho lưu trữ dựa trên đĩa với I/O khối lớn
- Low tree height even with billions of records
Chiều cao cây thấp ngay cả với hàng tỷ bản ghi
- Consistent O(log n) search, insert, delete performance
Hiệu suất tìm kiếm, chèn, xóa nhất quán O(log n)
- Cache-friendly due to spatial locality
Thân thiện với cache nhờ tính cục bộ không gian
- Self-balancing, no manual rebalancing needed
Tự động cân bằng, không cần tái cân bằng thủ công
- More complex than BST for in-memory implementation
Phức tạp hơn BST cho cài đặt trong bộ nhớ
- Higher overhead for small datasets
Overhead lớn hơn cho tập dữ liệu nhỏ
- Split/merge operations have significant cost
Thao tác tách/gộp có chi phí đáng kể
- Space utilization not optimal (nodes can be half empty)
Sử dụng không gian không tối ưu (nút có thể nửa trống)
- MySQL InnoDB: B+ Tree indexes for primary and secondary keys
MySQL InnoDB: B+ Tree indexes cho khóa chính và phụ
- PostgreSQL: B-Tree is the default index type
PostgreSQL: B-Tree là loại index mặc định
- SQLite: B-Tree for tables, B+ Tree for indexes
SQLite: B-Tree cho bảng, B+ Tree cho index
- NTFS / ext4: File system directory indexing
NTFS / ext4: Index thư mục hệ thống tập tin
- MongoDB: B-Tree indexes (WiredTiger engine)
MongoDB: B-Tree indexes (engine WiredTiger)
- Oracle Database: B* Tree (variant with smarter splits)
Oracle Database: B* Tree (biến thể với tách thông minh hơn)
- CouchDB: B+ Tree for views and indexes
CouchDB: B+ Tree cho views và indexes
- Btrfs: B-Tree filesystem for Linux
Btrfs: B-Tree filesystem cho Linux
Khi thiết kế hệ thống cơ sở dữ liệu, hãy cân nhắc: (1) Kích thước khối đĩa để chọn bậc tối ưu, (2) Tỷ lệ đọc/ghi để quyết định B-Tree hay B+ Tree, (3) Loại truy vấn phổ biến nhất (điểm vs khoảng).