So sánh Regular Table và Hypertable trong TimescaleDB
Khi làm việc với dữ liệu chuỗi thời gian (Time-Series), việc hiểu sự khác biệt giữa bảng thông thường (Regular Table) và Hypertable là nền tảng để tối ưu hiệu năng.
Regular Table lưu trữ dữ liệu theo cấu trúc phẳng, nơi mọi dòng dữ liệu đều nằm chung trong một file vật lý duy nhất. Khi dữ liệu tăng lên hàng triệu hoặc hàng tỷ dòng, hiệu suất truy vấn giảm mạnh do cơ sở dữ liệu phải quét toàn bộ file để tìm kiếm.
Hypertable trong TimescaleDB không phải là một bảng vật lý mới, mà là một lớp trừu tượng (abstraction) nằm trên nhiều bảng vật lý con (chunks). TimescaleDB tự động chia nhỏ dữ liệu dựa trên một hoặc nhiều chiều (dimensions) như thời gian và không gian.
Khi bạn chèn dữ liệu vào Hypertable, hệ thống tự động định tuyến (route) dòng dữ liệu đó vào chunk phù hợp nhất dựa trên giá trị của column thời gian và các dimension khác.
Khác biệt cốt lõi: Regular Table phù hợp cho dữ liệu giao dịch (OLTP) với số lượng nhỏ. Hypertable được thiết kế cho dữ liệu cảm biến, log, hoặc metric với khối lượng khổng lồ, giúp giảm đáng kể thời gian quét và tăng tốc độ ghi (write throughput).
Để verify sự khác biệt này, bạn sẽ thấy Hypertable hiển thị cấu trúc các chunk con trong catalog, trong khi Regular Table chỉ là một bảng đơn lẻ.
Cấu trúc dữ liệu: Timestamp Column và Dimension
Trước khi tạo Hypertable, bạn cần xác định rõ cấu trúc dữ liệu nguồn. Một Hypertable bắt buộc phải có ít nhất một cột thời gian (timestamp column) để làm trục phân vùng chính.
Column thời gian thường có kiểu dữ liệu là TIMESTAMP hoặc TIMESTAMPTZ (recommended). TimescaleDB sử dụng cột này để xác định chunk nào sẽ chứa dữ liệu.
Bên cạnh thời gian, bạn có thể thêm các Dimension khác (ví dụ: device_id, location, sensor_type). Điều này tạo ra cơ chế phân vùng đa chiều (multi-dimensional partitioning), giúp tối ưu hóa truy vấn khi bạn lọc dữ liệu theo cả thời gian và thực thể.
Quy tắc đặt tên: Cột thời gian nên đặt tên rõ ràng như time, timestamp, hoặc created_at để hệ thống nhận diện dễ dàng, dù về mặt kỹ thuật bạn có thể đặt tên tùy ý.
Bạn cần tạo một bảng thông thường trước, sau đó nâng cấp nó thành Hypertable. Dữ liệu hiện có trong bảng thường sẽ tự động được di chuyển vào các chunks của Hypertable trong quá trình chuyển đổi.
Verify cấu trúc: Kiểm tra kiểu dữ liệu của cột thời gian phải là timestamp with time zone để đảm bảo tính nhất quán và chính xác về múi giờ.
Thực hành tạo Hypertable với lệnh create_hypertable()
Bây giờ chúng ta sẽ thực thi các lệnh SQL để tạo bảng mẫu và chuyển đổi nó thành Hypertable. Giả sử chúng ta đang lưu trữ dữ liệu nhiệt độ từ các cảm biến IoT.
Bước 1: Tạo bảng thông thường chứa các trường dữ liệu cần thiết. Đảm bảo kết nối vào database demo_timescale hoặc database của bạn.
Command tạo bảng mẫu:
CREATE TABLE IF NOT EXISTS conditions (
time TIMESTAMPTZ NOT NULL,
device_id TEXT NOT NULL,
temperature NUMERIC,
humidity NUMERIC,
location TEXT
);
Kết quả mong đợi: PostgreSQL trả về thông báo CREATE TABLE, xác nhận bảng conditions đã được tạo thành công.
Bước 2: Chèn một vài dòng dữ liệu mẫu để kiểm tra tính khả thi trước khi chuyển đổi.
INSERT INTO conditions (time, device_id, temperature, humidity, location)
VALUES
('2024-01-01 10:00:00+07', 'sensor_01', 25.5, 60.0, 'Hanoi'),
('2024-01-01 10:05:00+07', 'sensor_02', 26.1, 58.5, 'HCMC'),
('2024-01-02 10:00:00+07', 'sensor_01', 24.8, 62.0, 'Hanoi');
Kết quả mong đợi: PostgreSQL trả về INSERT 0 3, xác nhận 3 dòng dữ liệu đã được ghi vào bảng thường.
Bước 3: Gọi hàm create_hypertable() để biến bảng conditions thành Hypertable. Tham số bắt buộc là tên bảng và tên cột thời gian.
SELECT create_hypertable('conditions', 'time');
Kết quả mong đợi: PostgreSQL trả về SELECT 1. Đây là tín hiệu quan trọng nhất, nghĩa là Hypertable đã được tạo và dữ liệu cũ đã được phân vùng tự động.
Bước 4: Mở rộng với Dimension thứ hai (ví dụ: device_id) để tối ưu truy vấn theo từng thiết bị.
SELECT add_hypertable_column('conditions', 'device_id');
Kết quả mong đợi: PostgreSQL trả về SELECT 1, xác nhận device_id đã được thêm làm dimension phân vùng phụ.
Hiểu cơ chế phân vùng tự động theo thời gian
Sau khi thực hiện create_hypertable(), TimescaleDB sẽ tự động chia dữ liệu trong bảng conditions thành nhiều bảng vật lý con gọi là chunks.
Mỗi chunk tương ứng với một khoảng thời gian nhất định (mặc định là 1 tháng cho dữ liệu mới). Khi dữ liệu mới được chèn vào, hệ thống tự động tính toán chunk nào cần nhận dữ liệu đó dựa trên giá trị timestamp.
Khác với việc phân vùng thủ công (Manual Partitioning) trong PostgreSQL truyền thống, Hypertable ẩn đi sự phức tạp này. Bạn vẫn truy vấn như một bảng duy nhất, nhưng engine phía sau chỉ quét các chunk liên quan đến khoảng thời gian bạn yêu cầu.
Điều này giúp giảm thiểu I/O disk và RAM tiêu thụ khi thực hiện các truy vấn WHERE time BETWEEN ... AND ... trên dữ liệu lịch sử lớn.
Để hiểu rõ cơ chế này, bạn cần xem danh sách các chunks đã được tạo ra từ bảng conditions của mình.
Command để liệt kê các chunks:
\d _timescaledb_internal.*conditions*
Kết quả mong đợi: Bạn sẽ thấy danh sách nhiều bảng có tên dạng _timescaledb_internal._hyper_1_1_chunk, _timescaledb_internal._hyper_1_2_chunk... Đây chính là các bảng vật lý chứa dữ liệu đã được phân vùng.
Cách verify kết quả cuối cùng: Kiểm tra xem dữ liệu đã được phân bổ vào các chunk chưa bằng lệnh SQL sau.
SELECT chunk_name, COUNT(*) as row_count
FROM _timescaledb_catalog.chunk
WHERE hypertable_name = 'conditions'
GROUP BY chunk_name;
Kết quả mong đợi: Bạn sẽ thấy một hoặc nhiều dòng kết quả, mỗi dòng đại diện cho một chunk chứa số lượng hàng tương ứng với dữ liệu bạn đã chèn. Nếu chỉ có 1 chunk, nghĩa là dữ liệu nằm trong cùng một khoảng thời gian mặc định.
Điều hướng series:
Mục lục: Series: Triển khai Database Time-Series với TimescaleDB và Ubuntu 24.04
« Phần 2: Cài đặt và khởi tạo TimescaleDB trên Ubuntu 24.04
Phần 4: Tối ưu hiệu năng lưu trữ với Compression và Retention »