Phân biệt cơ chế Row-Oriented và Column-Oriented trong CockroachDB
Trong mô hình Row-Oriented, dữ liệu của một hàng (row) được lưu trữ liên tiếp nhau trên đĩa. Điều này tối ưu hóa các thao tác INSERT, UPDATE và các truy vấn SELECT lấy toàn bộ hàng hoặc một số ít cột dựa trên Primary Key.
Ngược lại, Column-Oriented (thường dùng cho Analytics) lưu trữ dữ liệu theo từng cột riêng biệt. Mô hình này phù hợp với các truy vấn tổng hợp (aggregations) trên tập dữ liệu lớn nhưng lại kém hiệu năng khi cần đọc/ghi nhiều cột của một hàng duy nhất.
Để xác nhận cluster hiện tại đang hoạt động theo mô hình Row-Oriented mặc định, ta kiểm tra định dạng lưu trữ của một bảng mẫu. CockroachDB mặc định sử dụng Row-Oriented cho tất cả các bảng thông thường.
Thực hiện lệnh kiểm tra cấu trúc bảng để xác nhận:
cockroach sql --insecure -e "SHOW CREATE TABLE employees;"
Kết quả mong đợi: Lệnh trả về lệnh CREATE TABLE với các cột được liệt kê theo thứ tự. Nếu không có từ khóa "COLUMN" hoặc cấu trúc đặc biệt của Table API, đây là bảng Row-Oriented tiêu chuẩn. Dữ liệu sẽ được lưu trữ theo nhóm các thuộc tính của một Primary Key.
Cấu hình Zone Configuration để tối ưu vùng nhớ cho dữ liệu hàng
Zone Configuration trong CockroachDB cho phép ta điều chỉnh các tham số như số lượng bản sao (replicas), mức độ ưu tiên (priority) và các tham số I/O cụ thể cho một tablespace hoặc một bảng nhất định.
Đối với mô hình Row-Oriented, việc quan trọng nhất là đảm bảo các replica của dữ liệu hàng được phân tán đều để giảm xung đột I/O (write contention) khi ghi vào cùng một node, đồng thời tối ưu hóa việc đọc toàn bộ hàng.
Chúng ta sẽ tạo một file cấu hình YAML để gán một zone config riêng cho bảng `employees` với số lượng replica là 3 và tăng mức độ ưu tiên đọc/ghi.
Đầu tiên, tạo file cấu hình với đường dẫn đầy đủ `/tmp/employees_zone_config.yaml`:
cat > /tmp/employees_zone_config.yaml
Kết quả mong đợi: File YAML được tạo thành công tại `/tmp/employees_zone_config.yaml` với các tham số cấu hình rõ ràng.
Tiếp theo, áp dụng file cấu hình này vào database `bank` (giả sử bảng `employees` nằm trong db này) thông qua lệnh CLI:
cockroach sql --insecure -e "ALTER TABLE bank.employees CONFIGURE ZONE USING zone_file='/tmp/employees_zone_config.yaml';"
Kết quả mong đợi: Lệnh trả về `ALTER TABLE` thành công, không báo lỗi cú pháp. CockroachDB sẽ tự động phân chia lại các range của bảng `employees` để tuân thủ cấu hình mới.
Để verify kết quả, kiểm tra zone config hiện hành của bảng:
cockroach sql --insecure -e "SHOW ZONE CONFIGURATION FOR TABLE bank.employees;"
Kết quả mong đợi: Output hiển thị các tham số `num_replicas: 3` và `priority: 100` đã được áp dụng cho bảng `employees`.
Điều chỉnh chỉ mục (Index) phù hợp cho truy vấn Row-Oriented
Trong mô hình Row-Oriented, Primary Key là chỉ mục chính và quan trọng nhất. Mọi truy vấn tìm kiếm theo Primary Key đều rất nhanh vì dữ liệu được tổ chức theo thứ tự này.
Vấn đề phát sinh khi truy vấn theo các cột không phải Primary Key. Lúc này, CockroachDB phải quét toàn bộ bảng (full table scan) nếu không có chỉ mục phụ (secondary index). Việc tạo index phụ cho các cột thường dùng trong điều kiện WHERE là bắt buộc để tối ưu hiệu năng.
Chúng ta sẽ tạo một chỉ mục phụ cho cột `email` vì đây là trường thường xuyên được dùng để tra cứu thông tin người dùng (Row-Oriented query pattern).
Thực hiện lệnh tạo chỉ mục:
cockroach sql --insecure -e "CREATE INDEX IF NOT EXISTS idx_employees_email ON bank.employees (email) STORING (first_name, last_name);"
Giải thích: Từ khóa `STORING` cho phép chúng ta nhúng thêm các cột `first_name` và `last_name` vào cấu trúc của index này. Điều này giúp thực hiện "covering index" scan, nghĩa là database có thể trả về kết quả chỉ từ index mà không cần phải đi đọc lại dữ liệu gốc (row) trong bảng chính, giảm đáng kể I/O.
Kết quả mong đợi: Lệnh trả về `CREATE INDEX` thành công. Chỉ mục mới được tạo và bắt đầu lập chỉ mục lại dữ liệu cũ (backfill) trong nền.
Kiểm tra xem chỉ mục đã được tạo và trạng thái của nó:
cockroach sql --insecure -e "SHOW INDEXES FROM bank.employees;"
Kết quả mong đợi: Output hiển thị danh sách các chỉ mục, bao gồm `idx_employees_email` với trạng thái `ready` (không còn đang backfill).
Phân tích kế hoạch thực thi (EXPLAIN) để tối ưu query
Để đảm bảo các thay đổi về Zone Config và Index đã phát huy tác dụng, chúng ta cần sử dụng lệnh `EXPLAIN` để xem cách CockroachDB thực thi một truy vấn cụ thể.
Mục tiêu là chứng minh rằng khi truy vấn theo `email`, hệ thống sử dụng chỉ mục `idx_employees_email` thay vì quét toàn bộ bảng (`scan` toàn bộ range).
Thực hiện truy vấn mẫu với cờ `ANALYZE` để lấy thêm thông tin thống kê thực tế về thời gian và số lượng dòng:
cockroach sql --insecure -e "EXPLAIN (VERBOSE, ANALYZE) SELECT first_name, last_name FROM bank.employees WHERE email = 'john.doe@example.com';"
Kết quả mong đợi: Output hiển thị cây kế hoạch thực thi (Plan Tree). Bạn cần tìm dòng chứa `IndexJoin` hoặc `Scan` trên chỉ mục `idx_employees_email`. Nếu thấy `Scan` trên `primary` (bảng gốc) mà không qua index, nghĩa là query chưa tối ưu.
Để so sánh hiệu năng trước và sau khi tạo index, hãy chạy cùng một query nhưng giả lập việc không có index (bằng cách tạm thời tắt index hoặc dùng query khác) và so sánh chỉ số `estimated rows` và `actual rows`.
Một ví dụ về output tối ưu sẽ hiển thị:
IndexJoin
-> Scan idx_employees_email (estimated rows: 1)
Filter: email = 'john.doe@example.com'
-> TableAccess (primary) (estimated rows: 1)
Filter: primary key match
Kết quả mong đợi: Cây kế hoạch phải bắt đầu bằng `IndexJoin` hoặc `Scan` trên chỉ mục phụ, chứng tỏ CockroachDB đã chọn đúng đường đi để truy cập dữ liệu Row-Oriented. Thời gian thực thi (Execution time) trong phần `ANALYZE` phải ở mức thấp (dưới 10ms cho dữ liệu nhỏ).
Để xác nhận cuối cùng rằng index đang được sử dụng, kiểm tra thống kê thực thi của index:
cockroach sql --insecure -e "SELECT * FROM crdb_internal.node_index_usage_stats WHERE table_name = 'employees' AND index_name = 'idx_employees_email' LIMIT 5;"
Kết quả mong đợi: Bảng thống kê trả về số lần index được truy cập (`index_scan_count`) lớn hơn 0, khẳng định index đã được sử dụng trong các query gần đây.
Điều hướng series:
Mục lục: Series: Triển khai Database Row-Oriented với CockroachDB trên Ubuntu 24.04
« Phần 3: Khởi tạo cluster đơn nút và cấu hình lưu trữ Row-Oriented
Phần 5: Triển khai cluster đa nút và cấu hình replication cho dữ liệu »