时序数据库深度对比
一、为什么需要专门的时序数据库
1.1 传统数据库的局限
MySQL/PostgreSQL处理时序数据:
CREATE TABLE sensor_data (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
timestamp DATETIME,
sensor_id INT,
temperature FLOAT,
INDEX idx_time (timestamp)
);
-- 查询1小时平均值
SELECT AVG(temperature)
FROM sensor_data
WHERE timestamp >= '2024-01-27 10:00:00'
AND timestamp < '2024-01-27 11:00:00'
AND sensor_id = 1;
问题:
- ❌ 写入性能差(B-Tree索引开销大)
- ❌ 存储空间大(无压缩优化)
- ❌ 聚合查询慢(全表扫描)
- ❌ 数据保留困难(删除旧数据锁表)
1.2 时序数据特征
- 时间排序:数据按时间戳自然有序
- 只追加:几乎不修改历史数据
- 高写入:IOT传感器每秒数千条
- 范围查询:常查"过去1小时"而非单条
- 降采样:旧数据可降低精度
二、主流时序数据库对比
2.1 总览表格
| 特性 | InfluxDB | TimescaleDB | Prometheus | QuestDB | VictoriaMetrics |
|---|---|---|---|---|---|
| 类型 | 专用TSDB | PG扩展 | 监控专用 | 专用TSDB | 监控专用 |
| 查询语言 | InfluxQL/Flux | SQL | PromQL | SQL | PromQL |
| 写入性能 | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 查询性能 | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 压缩率 | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 分布式 | 商业版 | ✅ | ✅ | ❌ | ✅ |
| 开源 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 学习曲线 | 中 | 低(SQL) | 中 | 低(SQL) | 中 |
三、InfluxDB详解
3.1 数据模型
概念:
- Measurement:类似表(如"temperature")
- Tags:索引字段(如location、sensor_id)
- Fields:实际值(如value、humidity)
- Timestamp:纳秒精度
示例:
measurement: cpu
tags: host=server01, region=us-west
fields: usage_idle=90.5, usage_user=5.2
timestamp: 1706342145000000000
3.2 写入优化
Line Protocol(文本格式):
# 格式:measurement,tag1=value1,tag2=value2 field1=value1,field2=value2 timestamp
cpu,host=server01,region=us-west usage_idle=90.5,usage_user=5.2 1706342145000000000
memory,host=server01 used_percent=65.3 1706342145000000000
批量写入:
from influxdb_client import InfluxDBClient, Point
from influxdb_client.client.write_api import SYNCHRONOUS
client = InfluxDBClient(url="http://localhost:8086", token="my-token")
write_api = client.write_api(write_options=SYNCHRONOUS)
# 批量写入(推荐)
points = []
for i in range(1000):
point = Point("sensor_data") \
.tag("sensor_id", "sensor_001") \
.field("temperature", 25.5 + random.random()) \
.time(datetime.utcnow())
points.append(point)
write_api.write(bucket="my-bucket", record=points)
性能:
- 单机:100,000 - 500,000 点/秒
- 批量大小:5000-10000点为佳
- 内存缓存:默认1GB
3.3 查询语言对比
InfluxQL(类SQL):
SELECT MEAN(temperature)
FROM sensor_data
WHERE time > now() - 1h
AND sensor_id = 'sensor_001'
GROUP BY time(5m)
Flux(函数式):
from(bucket: "my-bucket")
|> range(start: -1h)
|> filter(fn: (r) => r._measurement == "sensor_data")
|> filter(fn: (r) => r.sensor_id == "sensor_001")
|> aggregateWindow(every: 5m, fn: mean)
3.4 数据保留策略
自动删除旧数据:
# 创建保留策略:7天数据
influx bucket create \
--name my-bucket \
--retention 7d
# 无限保留
influx bucket create \
--name archive \
--retention 0
降采样(Downsampling):
// 任务:每小时将1分钟数据聚合为1小时数据
option task = {name: "downsample", every: 1h}
from(bucket: "raw-data")
|> range(start: -1h)
|> aggregateWindow(every: 1h, fn: mean)
|> to(bucket: "downsampled")
四、TimescaleDB详解
4.1 架构设计
Hypertable(超表):
-- 创建普通表
CREATE TABLE conditions (
time TIMESTAMPTZ NOT NULL,
location TEXT NOT NULL,
temperature DOUBLE PRECISION,
humidity DOUBLE PRECISION
);
-- 转换为超表(自动分区)
SELECT create_hypertable('conditions', 'time');
自动分区(Chunks):
- 默认按时间分片(如每7天一个chunk)
- 透明查询:SELECT时无需指定分区
4.2 压缩
启用压缩:
-- 设置压缩策略
ALTER TABLE conditions SET (
timescaledb.compress,
timescaledb.compress_segmentby = 'location'
);
-- 自动压缩7天前的数据
SELECT add_compression_policy('conditions', INTERVAL '7 days');
效果:
- 压缩率:10-100倍
- 查询:解压缩自动进行
- 权衡:写入变为只读
4.3 连续聚合(Continuous Aggregates)
实时物化视图:
-- 创建1小时聚合视图
CREATE MATERIALIZED VIEW conditions_hourly
WITH (timescaledb.continuous) AS
SELECT time_bucket('1 hour', time) AS hour,
location,
AVG(temperature) AS avg_temp,
MAX(temperature) AS max_temp
FROM conditions
GROUP BY hour, location;
-- 查询(自动使用预聚合)
SELECT * FROM conditions_hourly
WHERE hour > NOW() - INTERVAL '1 day';
更新策略:
-- 每小时更新
SELECT add_continuous_aggregate_policy('conditions_hourly',
start_offset => INTERVAL '2 hours',
end_offset => INTERVAL '1 hour',
schedule_interval => INTERVAL '1 hour');
4.4 优势
1. SQL兼容性:
- 现有PostgreSQL知识直接可用
- 支持JOIN、子查询、窗口函数
2. 生态丰富:
- PostGIS(地理空间)
- pg_cron(定时任务)
- 所有PG扩展
3. ACID事务:
- 强一致性保证
- 适合金融、医疗等严格场景
五、Prometheus详解
5.1 数据模型
Metric Name + Labels:
http_requests_total{method="GET", endpoint="/api", status="200"} 12345
Metric类型:
- Counter:只增不减(如请求总数)
- Gauge:可增可减(如CPU使用率)
- Histogram:分布统计(如响应时间)
- Summary:类似Histogram,客户端计算
5.2 Pull模型
架构:
应用程序(暴露/metrics端点)
↑
Prometheus Server(定期抓取)
↓
查询 / 告警 / 可视化
配置:
# prometheus.yml
scrape_configs:
- job_name: 'my-app'
scrape_interval: 15s
static_configs:
- targets: ['localhost:8080', 'localhost:8081']
应用侧暴露指标:
from prometheus_client import Counter, Gauge, start_http_server
# 定义指标
requests_total = Counter('http_requests_total', 'Total HTTP requests', ['method', 'endpoint'])
cpu_usage = Gauge('cpu_usage_percent', 'CPU usage percentage')
# 更新指标
requests_total.labels(method='GET', endpoint='/api').inc()
cpu_usage.set(75.3)
# 启动HTTP服务器暴露指标
start_http_server(8000) # /metrics端点
5.3 PromQL查询
基础:
# 当前值
http_requests_total
# 过滤
http_requests_total{method="GET", status="200"}
# 速率(每秒请求数)
rate(http_requests_total[5m])
# 聚合
sum(rate(http_requests_total[5m])) by (endpoint)
高级:
# 99百分位响应时间
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))
# 预测(线性回归)
predict_linear(node_filesystem_free_bytes[1h], 4 * 3600) # 4小时后
5.4 限制
- ❌ 单机扩展有限(推荐<1000节点)
- ❌ 长期存储需外部方案(Thanos, Cortex, VictoriaMetrics)
- ❌ 查询高基数数据慢(如user_id标签)
六、QuestDB详解
6.1 性能极致
写入速度:
- 单线程:4,000,000 行/秒
- 多线程:10,000,000+ 行/秒
- 延迟:微秒级
查询速度:
- 10亿行聚合:<1秒
- 列式存储 + SIMD优化
6.2 SQL扩展
SAMPLE BY(时间聚合):
SELECT timestamp, avg(temperature)
FROM sensor_data
WHERE timestamp > '2024-01-01'
SAMPLE BY 1h; -- 按1小时聚合
LATEST ON(最新值):
SELECT * FROM trades
LATEST ON timestamp PARTITION BY symbol; -- 每个交易对最新价格
6.3 时间序列JOIN
ASOF JOIN(时间对齐):
-- 将两个不对齐的时间序列JOIN
SELECT *
FROM orders
ASOF JOIN quotes
ON orders.symbol = quotes.symbol;
-- 自动找到quotes中<=orders.time的最近记录
七、性能基准测试
7.1 写入性能
测试场景:1000传感器,每秒1次,持续1小时
| 数据库 | 写入速率(点/秒) | CPU使用率 | 内存使用 |
|---|---|---|---|
| QuestDB | 1,000,000 | 25% | 512MB |
| InfluxDB | 500,000 | 40% | 2GB |
| TimescaleDB | 300,000 | 60% | 4GB |
| Prometheus | 200,000 | 35% | 1GB |
| PostgreSQL | 50,000 | 80% | 8GB |
7.2 查询性能
测试查询:1亿行数据,计算过去7天每小时平均值
| 数据库 | 查询时间 | 备注 |
|---|---|---|
| QuestDB | 0.8秒 | 列式存储+SIMD |
| TimescaleDB | 2.3秒 | 连续聚合优化 |
| InfluxDB | 3.5秒 | 索引优化 |
| PostgreSQL | 45秒 | 全表扫描 |
7.3 压缩率
原始数据:1GB(1000万条记录)
| 数据库 | 压缩后大小 | 压缩率 |
|---|---|---|
| QuestDB | 15MB | 67x |
| InfluxDB | 25MB | 40x |
| TimescaleDB | 50MB | 20x |
| Prometheus | 30MB | 33x |
八、选型决策树
8.1 按场景选择
监控场景(Prometheus):
✅ 主要监控系统指标
✅ 需要告警功能
✅ 规模<1000节点
✅ Pull模型可接受
IoT场景(InfluxDB/QuestDB):
✅ 大量传感器(百万级)
✅ 高写入频率
✅ 需要复杂查询
✅ 数据降采样需求
金融场景(QuestDB/TimescaleDB):
✅ 极低延迟要求(<1ms)
✅ 时间序列JOIN(如订单+报价)
✅ ACID事务需求
✅ SQL分析师友好
通用场景(TimescaleDB):
✅ 已有PostgreSQL经验
✅ 需要关系型功能(JOIN、事务)
✅ 长期存储
✅ 地理空间数据
8.2 按数据量选择
| 数据量/天 | 推荐 |
|---|---|
| <1GB | 任意(PostgreSQL也可) |
| 1-100GB | InfluxDB / TimescaleDB |
| 100GB-1TB | TimescaleDB(分布式) / InfluxDB Enterprise |
| >1TB | QuestDB(单机) / VictoriaMetrics(集群) |
九、最佳实践
9.1 Schema设计
InfluxDB:
✅ 高基数放fields(如user_id)
❌ 高基数放tags(会爆炸)
✅ 低基数放tags(如region: us/eu/asia)
✅ Measurement按数据类型分(cpu, memory分开)
TimescaleDB:
-- ✅ 时间戳作为第一列
-- ✅ 高基数列不作为分区键
-- ✅ 启用压缩
CREATE TABLE metrics (
time TIMESTAMPTZ NOT NULL,
metric_name TEXT,
value DOUBLE PRECISION,
tags JSONB
);
SELECT create_hypertable('metrics', 'time');
ALTER TABLE metrics SET (timescaledb.compress);
9.2 查询优化
避免高基数聚合:
-- ❌ 慢(100万个user_id)
SELECT user_id, COUNT(*)
FROM events
GROUP BY user_id;
-- ✅ 快(预聚合)
SELECT region, COUNT(*)
FROM events
GROUP BY region;
使用连续聚合:
-- 预计算小时/天聚合,避免实时计算
CREATE MATERIALIZED VIEW metrics_hourly ...
9.3 数据保留
分层存储:
原始数据:保留7天
1分钟聚合:保留30天
1小时聚合:保留1年
1天聚合:永久
实现:
-- TimescaleDB
SELECT add_retention_policy('raw_data', INTERVAL '7 days');
-- InfluxDB
influx bucket update --id xxx --retention 7d
十、总结对比
| 维度 | InfluxDB | TimescaleDB | Prometheus | QuestDB |
|---|---|---|---|---|
| 最适合 | IoT, 通用TSDB | 需要SQL和事务 | 系统监控 | 高性能交易 |
| 优势 | 易用、云原生 | PostgreSQL生态 | 告警、Pull模型 | 极致性能 |
| 劣势 | 分布式收费 | 学习曲线(PG) | 单机扩展限制 | 生态较新 |
| 社区 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| 成熟度 | 10年+ | 5年+ | 10年+ | 5年+ |
终极建议:
- 🥇 新项目+IoT:InfluxDB(易用性好)
- 🥈 已有PG:TimescaleDB(无缝集成)
- 🥉 监控专用:Prometheus(生态最强)
- 🚀 性能极客:QuestDB(速度之王)
混合使用:
数据采集 → Kafka → 分流
↓ ↓ ↓
实时监控 长期存储 实时查询
Prometheus TimescaleDB QuestDB
选择时序数据库的核心:理解数据特征 + 匹配业务需求 + 团队技术栈。