Các Thao Tác Lõi trên Hệ Thống Lưu Trữ Dữ Liệu Thời Gian
Cơ sở dữ liệu chuỗi thời gian (Time-Series Database – TSDB) được thiết kế đặc biệt để xử lý khối lượng lớn điểm dữ liệu gắn nhãn thời gian. Các thao tác cơ bản không chỉ giới hạn ở CRUD truyền thống mà còn bao gồm tối ưu hóa truy vấn theo thời gian, quản lý vòng đời dữ liệu và hỗ trợ phân tích xu hướng. Dưới đây là các nhóm thao tác chính, minh họa qua cách triển khai trên ba nền tảng phổ biến: TimescaleDB (dựa trên PostgreSQL), InfluxDB (SQL-like và Flux), và TDengine (SQL-native với kiến trúc siêu bảng).1. Ghi dữ liệu hiệu quả
Ghi dữ liệu là bước đầu tiên và thường là yêu cầu hiệu năng cao nhất trong hệ thống giám sát IoT hoặc cảm biến môi trường.
- Ghi hàng loạt theo khối: Thay vì chèn từng bản ghi, nên nhóm dữ liệu theo khoảng thời gian hoặc thiết bị. Ví dụ, trong TDengine:
-- Chèn 500 mẫu từ 10 cảm biến cùng lúc
INSERT INTO sensors_001 VALUES
('2025-07-01T08:00:00', 24.7, 62.1),
('2025-07-01T08:00:05', 24.8, 61.9),
...
('2025-07-01T08:08:10', 25.2, 60.5);
- Tự động tạo bảng con: Khi sử dụng siêu bảng (super table), hệ thống tự sinh bảng con dựa trên tag (ví dụ:
location="greenhouse_a") mà không cần khai báo thủ công. - Hỗ trợ định dạng thời gian linh hoạt: Nhận dạng
NOW(), timestamp nguyên (giây/millisecond), hoặc chuỗi ISO8601 — tùy vào cài đặt cấu hình.
2. Truy vấn có ngữ cảnh thời gian
Khác với CSDL quan hệ thông thường, TSDB ưu tiên các truy vấn có điều kiện thời gian làm bộ lọc đầu tiên.
- Lọc theo khoảng thời gian: Luôn đặt điều kiện
WHERE time >= ... AND time <= ...để tận dụng phân vùng theo thời gian.
-- TimescaleDB: truy vấn dữ liệu trong 2 giờ gần nhất
SELECT sensor_id, AVG(temperature) AS avg_t
FROM sensor_readings
WHERE time >= NOW() - INTERVAL '2 HOURS'
GROUP BY sensor_id;
- Tổng hợp theo cửa sổ thời gian: Sử dụng hàm như
time_bucket()(TimescaleDB),aggregateWindow()(InfluxDB v3), hoặcINTERVAL(TDengine).
-- InfluxDB Flux: tính trung bình nhiệt độ mỗi 15 phút
from(bucket: "farm_data")
|> range(start: -1d)
|> filter(fn: (r) => r._measurement == "env" and r._field == "temp")
|> aggregateWindow(every: 15m, fn: mean)
3. Quản trị vòng đời dữ liệu
Do đặc thù dữ liệu tăng theo thời gian, việc dọn dẹp và di chuyển dữ liệu cũ là bắt buộc.
- Xóa dữ liệu theo thời gian:
-- TimescaleDB: xóa các chunk cũ hơn 90 ngày
SELECT drop_chunks('sensor_readings', older_than => INTERVAL '90 days');
-- TDengine: xóa bản ghi trước một mốc cụ thể
DELETE FROM sensors WHERE ts < '2025-04-01';
- Chính sách lưu trữ tự động: Thiết lập retention policy để hệ thống tự động loại bỏ hoặc nén dữ liệu sau thời hạn quy định — giảm chi phí lưu trữ và tăng tốc độ truy vấn.
4. Tối ưu hiệu năng
Một số kỹ thuật nâng cao giúp duy trì hiệu suất khi quy mô dữ liệu vượt ngưỡng triệu bản ghi/giây:
- Phân vùng theo thời gian và thẻ (tag): Kết hợp hai chiều phân vùng giúp cả truy vấn thời gian lẫn truy vấn theo thiết bị đều nhanh.
- Mã hóa delta và nén cột: Với chuỗi giá trị gần nhau (ví dụ: nhiệt độ thay đổi chậm), lưu chênh lệch thay vì giá trị tuyệt đối; áp dụng LZ4 cho cột số thực.
- Bộ nhớ đệm kết quả truy vấn: Cache kết quả của các dashboard cố định (ví dụ: biểu đồ nhiệt độ trung bình theo khu vực) để tránh tính toán lặp.
5. Giám sát và bảo trì hệ thống
Các thao tác vận hành đảm bảo độ ổn định và khả năng mở rộng:
- Giám sát tài nguyên: Theo dõi dung lượng ổ đĩa cho từng hypertable/chunk, số lượng kết nối, và thời gian thực thi truy vấn chậm.
- Tự động hóa tác vụ định kỳ: Lên lịch job để sao lưu dữ liệu, tái cân bằng phân vùng hoặc cập nhật chỉ mục.
So sánh cú pháp giữa các hệ thống
| Thao tác | TimescaleDB | InfluxDB (v2+) | TDengine |
|---|---|---|---|
| Ghi dữ liệu | INSERT INTO metrics |
line protocol hoặc Flux write |
INSERT INTO stb USING ... |
| Tổng hợp theo thời gian | time_bucket('1h', time) |
aggregateWindow(every: 1h) |
INTERVAL(1h) |
| Xóa dữ liệu cũ | drop_chunks(...) |
delete API hoặc retention policy |
DELETE FROM ... WHERE ts < ... |
Mô phỏng giám sát nông nghiệp: sinh dữ liệu và trực quan hóa
Dưới đây là phiên bản tối ưu hóa của kịch bản giám sát trang trại — tập trung vào tính thực tế và khả năng mở rộng.
Python: Sinh dữ liệu mô phỏng với mô hình sinh học
import numpy as np
import pandas as pd
from datetime import datetime, timedelta
def simulate_greenhouse_data(
start_dt: datetime = datetime(2025, 7, 1, 6, 0),
duration_hrs: int = 72,
interval_min: int = 3,
num_sensors: int = 80
):
# Tọa độ giả lập trong vùng nông nghiệp
coords = np.random.uniform(
low=[116.2, 39.9],
high=[116.4, 40.1],
size=(num_sensors, 2)
)
# Tạo chuỗi thời gian
timestamps = pd.date_range(
start=start_dt,
end=start_dt + timedelta(hours=duration_hrs),
freq=f'{interval_min}T'
)
data_rows = []
for i in range(num_sensors):
lon, lat = coords[i]
for ts in timestamps:
hour = ts.hour
# Mô hình nhiệt độ: dao động theo chu kỳ ngày/đêm + nhiễu Gauss
base_temp = 22 + 5 * np.sin((hour - 14) * np.pi / 12)
temp = round(base_temp + np.random.normal(0, 0.8), 1)
# Độ ẩm phụ thuộc nghịch vào nhiệt độ + yếu tố vị trí
hum_base = 75 - 0.6 * (temp - 22) + (lon - 116.3) * 20
humidity = round(np.clip(hum_base + np.random.normal(0, 2.5), 30, 95), 1)
data_rows.append({
'ts': ts,
'sensor_id': f'SEN_{i+1:03d}',
'lat': lat,
'lon': lon,
'temperature': temp,
'humidity': humidity
})
return pd.DataFrame(data_rows)
# Sinh và xuất dữ liệu
df_sim = simulate_greenhouse_data()
df_sim.to_csv('greenhouse_sim.csv', index=False)
HTML/JavaScript: Trực quan hóa tương tác với ECharts
Phiên bản frontend sử dụng echarts-gl để vẽ bản đồ nhiệt 3D và hỗ trợ tải lại dữ liệu động:
<script>
// Khởi tạo biểu đồ nhiệt độ
const tempChart = echarts.init(document.getElementById('tempHeatmap'));
const optionTemp = {
tooltip: { trigger: 'axis' },
visualMap: {
min: 15, max: 35,
calculable: true,
orient: 'horizontal',
left: 'center',
bottom: '10%'
},
xAxis3D: { type: 'category', data: positions },
yAxis3D: { type: 'category', data: ['Avg'] },
zAxis3D: { type: 'value' },
grid3D: { show: false },
series: [{
type: 'bar3D',
data: temperatureData.map((v, i) => [i, 0, v]),
shading: 'lambert'
}]
};
tempChart.setOption(optionTemp);
</script>
Khuyến nghị triển khai thực tế
- Viết dữ liệu: Luôn dùng batch insert với kích thước 100–1000 bản ghi/lần; tránh chèn đơn lẻ trong vòng lặp.
- Truy vấn: Đặt điều kiện thời gian luôn luôn đứng đầu trong mệnh đề
WHERE. - Lưu trữ: Áp dụng chiến lược "hot-warm-cold": dữ liệu mới trên SSD, dữ liệu 30–90 ngày trên HDD, dữ liệu >90 ngày trên object storage (S3/OSS).
- Giám sát: Thiết lập cảnh báo khi tỷ lệ chunk bị phân mảnh >15% hoặc thời gian query trung bình tăng >2x so với baseline.