对于您的 IoT 软总线系统(大数据量、高频写入、复杂查询),PostgreSQL 和 MySQL 也是值得考虑的选择。本文档分析它们在您场景下的适用性。
强大的 SQL 支持
时间序列数据支持
扩展性好
并发控制优秀
数据完整性
部署复杂度
资源占用
Qt 集成
写入性能
单机场景
广泛使用
性能优化
简单易用
Qt 集成
时间序列数据支持弱
JSON 支持较弱
部署复杂度
写入性能
扩展性
| 指标 | 描述 |
|---|---|
| 数据量 | TB 级别(持续采集) |
| 写入频率 | 高频(每秒数千到数万条) |
| 查询需求 | 复杂查询(多字段、时间范围、聚合) |
| 部署方式 | 单机应用 or 分布式? |
| 资源限制 | 内存、CPU 是否受限? |
| 方案 | 写入性能 | 查询能力 | 部署复杂度 | 资源占用 | 适用场景 |
|---|---|---|---|---|---|
| RocksDB | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 纯写入,简单查询 |
| SQLite | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 中小规模,单机应用 |
| RocksDB + SQLite | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 大数据量,单机应用 ⭐ 推荐 |
| PostgreSQL | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | 分布式,需要强查询 |
| PostgreSQL + TimescaleDB | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | 时间序列,分布式场景 ⭐ 推荐 |
| MySQL | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | 传统应用,简单场景 |
-- 批量插入示例
INSERT INTO raw_data (device_id, data, timestamp, creator, data_level)
VALUES
(1, 'data1', 1234567890, 'user1', 5),
(2, 'data2', 1234567891, 'user2', 6);
-- 性能:约 5-10万行/秒(取决于配置)
-- 批量插入示例(类似)
INSERT INTO raw_data (device_id, data, timestamp, creator, data_level)
VALUES
(1, 'data1', 1234567890, 'user1', 5),
(2, 'data2', 1234567891, 'user2', 6);
-- 性能:约 5-10万行/秒(取决于配置)
// 直接写入 RocksDB,无事务开销
m_rawDb->Put(key, value); // 性能:10-50万行/秒
// SQLite 索引异步写入
storeRawDataIndex(...); // 可批量写入,延迟低
结论:RocksDB 写入性能最优,PostgreSQL/MySQL 接近但需要事务开销。
-- 时间序列查询 + 聚合
SELECT
time_bucket('1 hour', timestamp) AS hour,
device_id,
COUNT(*) as count,
AVG(data_level) as avg_level,
creator
FROM raw_data
WHERE timestamp >= NOW() - INTERVAL '24 hours'
AND creator = '张三'
AND data_level >= 5
GROUP BY hour, device_id, creator
ORDER BY hour DESC;
-- 性能:优秀,TimescaleDB 自动优化
-- 类似查询
SELECT
DATE_FORMAT(timestamp, '%Y-%m-%d %H:00:00') AS hour,
device_id,
COUNT(*) as count,
AVG(data_level) as avg_level,
creator
FROM raw_data
WHERE timestamp >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
AND creator = '张三'
AND data_level >= 5
GROUP BY hour, device_id, creator
ORDER BY hour DESC;
-- 性能:一般,需要良好的索引设计
// SQLite 支持复杂 SQL
QString sql = R"(
SELECT rocksdb_key FROM raw_data_index
WHERE device_id = ?
AND create_time >= ?
AND create_time <= ?
AND creator = ?
AND data_level >= ?
ORDER BY create_time DESC
)";
// 然后从 RocksDB 读取实际数据
// 性能:良好,但需要两次查询
结论:PostgreSQL + TimescaleDB 查询能力最强,SQLite 次之,MySQL 一般。
1. 安装 PostgreSQL 服务器
sudo apt-get install postgresql
2. 创建数据库和用户
sudo -u postgres createdb soft_bus
sudo -u postgres psql -c "CREATE USER bus_user WITH PASSWORD 'password';"
3. 安装 TimescaleDB 扩展
sudo apt-get install timescaledb-postgresql-14
sudo timescaledb-tune
4. Qt 代码中连接
QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL");
db.setHostName("localhost");
db.setDatabaseName("soft_bus");
db.setUserName("bus_user");
db.setPassword("password");
1. 安装 MySQL 服务器
sudo apt-get install mysql-server
2. 创建数据库和用户
sudo mysql -e "CREATE DATABASE soft_bus;"
sudo mysql -e "CREATE USER 'bus_user'@'localhost' IDENTIFIED BY 'password';"
sudo mysql -e "GRANT ALL ON soft_bus.* TO 'bus_user'@'localhost';"
3. Qt 代码中连接
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("localhost");
db.setDatabaseName("soft_bus");
db.setUserName("bus_user");
db.setPassword("password");
1. RocksDB:已集成,无需额外安装
2. SQLite:Qt 自带,无需安装
3. 直接使用,零配置
结论:RocksDB + SQLite 部署最简单,PostgreSQL/MySQL 需要额外安装和配置。
| 方案 | 内存占用 | CPU 占用 | 磁盘占用 | 网络 |
|---|---|---|---|---|
| PostgreSQL | 较高(默认 1GB+) | 中等 | 正常 | 需要(如果远程) |
| MySQL | 较高(默认 512MB+) | 中等 | 正常 | 需要(如果远程) |
| RocksDB + SQLite | 低(可配置) | 低 | 正常 | 不需要 |
-- 需要编写迁移脚本,从 RocksDB 读取数据,写入 PostgreSQL
-- 可能耗时较长(TB级别数据)
-- 类似,需要迁移脚本
// 可以渐进式迁移:
// 1. 先启用 SQLite 索引(不影响现有 RocksDB)
// 2. 新数据同时写入 RocksDB 和 SQLite
// 3. 逐步迁移查询逻辑到 SQLite
// 4. 历史数据可选择性迁移
结论:混合架构迁移成本最低,PostgreSQL/MySQL 需要全量迁移。
推荐:RocksDB + SQLite 混合架构
理由:
适用条件:
推荐:PostgreSQL + TimescaleDB
理由:
适用条件:
推荐:MySQL
理由:
适用条件:
# 安装 PostgreSQL
sudo apt-get install postgresql-14
# 安装 TimescaleDB
sudo apt-get install timescaledb-postgresql-14
# 配置
sudo timescaledb-tune
# 启用扩展
sudo -u postgres psql -d postgres -c "CREATE EXTENSION IF NOT EXISTS timescaledb;"
-- 创建原始数据表
CREATE TABLE raw_data (
id BIGSERIAL,
device_id INTEGER NOT NULL,
data BYTEA NOT NULL,
timestamp TIMESTAMPTZ NOT NULL,
creator TEXT,
data_level INTEGER DEFAULT 0,
protocol_type TEXT,
metadata JSONB
);
-- 转换为时序表
SELECT create_hypertable('raw_data', 'timestamp');
-- 创建索引
CREATE INDEX idx_raw_data_device_time ON raw_data(device_id, timestamp DESC);
CREATE INDEX idx_raw_data_creator ON raw_data(creator);
CREATE INDEX idx_raw_data_level ON raw_data(data_level);
CREATE INDEX idx_raw_data_protocol ON raw_data(protocol_type);
-- 创建总线消息表
CREATE TABLE bus_messages (
id BIGSERIAL,
message_id TEXT UNIQUE NOT NULL,
source TEXT NOT NULL,
destination TEXT NOT NULL,
payload JSONB NOT NULL,
timestamp TIMESTAMPTZ NOT NULL,
creator TEXT,
data_level INTEGER DEFAULT 0,
protocol_type TEXT,
metadata JSONB
);
-- 转换为时序表
SELECT create_hypertable('bus_messages', 'timestamp');
-- 创建索引
CREATE INDEX idx_bus_msg_source_dest ON bus_messages(source, destination);
CREATE INDEX idx_bus_msg_time ON bus_messages(timestamp DESC);
CREATE INDEX idx_bus_msg_creator ON bus_messages(creator);
CREATE INDEX idx_bus_msg_level ON bus_messages(data_level);
// soft_bus_core.h
#include <QSqlDatabase>
#include <QSqlQuery>
class SoftBusCore : public QObject {
// ... 其他代码 ...
private:
QSqlDatabase m_pgDb; // PostgreSQL 连接
bool m_pgDbInitialized;
bool initPostgreSQL(const QString &connectionString);
void storeRawDataToPG(int deviceId, const QByteArray &data,
const QString &creator, int dataLevel,
const QString &protocolType);
};
// soft_bus_core.cpp
bool SoftBusCore::initPostgreSQL(const QString &connectionString) {
// 解析连接字符串:host=localhost;port=5432;dbname=soft_bus;user=bus_user;password=xxx
m_pgDb = QSqlDatabase::addDatabase("QPSQL", "postgresql_connection");
// 解析连接参数
QStringList parts = connectionString.split(';');
for (const QString &part : parts) {
QStringList kv = part.split('=');
if (kv.size() == 2) {
QString key = kv[0].trimmed();
QString value = kv[1].trimmed();
if (key == "host") m_pgDb.setHostName(value);
else if (key == "port") m_pgDb.setPort(value.toInt());
else if (key == "dbname") m_pgDb.setDatabaseName(value);
else if (key == "user") m_pgDb.setUserName(value);
else if (key == "password") m_pgDb.setPassword(value);
}
}
if (!m_pgDb.open()) {
qCritical() << "Failed to open PostgreSQL:" << m_pgDb.lastError().text();
return false;
}
m_pgDbInitialized = true;
return true;
}
void SoftBusCore::storeRawDataToPG(int deviceId, const QByteArray &data,
const QString &creator, int dataLevel,
const QString &protocolType) {
if (!m_pgDbInitialized || !m_pgDb.isOpen()) {
return;
}
QSqlQuery query(m_pgDb);
query.prepare(R"(
INSERT INTO raw_data (device_id, data, timestamp, creator, data_level, protocol_type)
VALUES (?, ?, NOW(), ?, ?, ?)
)");
query.addBindValue(deviceId);
query.addBindValue(data); // BYTEA 类型
query.addBindValue(creator.isEmpty() ? "system" : creator);
query.addBindValue(dataLevel);
query.addBindValue(protocolType);
if (!query.exec()) {
qWarning() << "Failed to store raw data to PostgreSQL:" << query.lastError().text();
}
}
// 复杂查询示例
QList<QByteArray> SoftBusCore::queryRawDataAdvancedPG(int deviceId,
qint64 startTime,
qint64 endTime,
const QString &creator,
int minLevel,
int maxLevel,
const QString &protocolType) {
QList<QByteArray> results;
if (!m_pgDbInitialized || !m_pgDb.isOpen()) {
return results;
}
QSqlQuery query(m_pgDb);
QString sql = "SELECT data FROM raw_data WHERE device_id = ?";
QVariantList bindValues;
bindValues << deviceId;
if (startTime > 0) {
sql += " AND timestamp >= ?";
bindValues << QDateTime::fromMSecsSinceEpoch(startTime);
}
if (endTime > 0) {
sql += " AND timestamp <= ?";
bindValues << QDateTime::fromMSecsSinceEpoch(endTime);
}
if (!creator.isEmpty()) {
sql += " AND creator = ?";
bindValues << creator;
}
if (minLevel >= 0) {
sql += " AND data_level >= ?";
bindValues << minLevel;
}
if (maxLevel >= 0) {
sql += " AND data_level <= ?";
bindValues << maxLevel;
}
if (!protocolType.isEmpty()) {
sql += " AND protocol_type = ?";
bindValues << protocolType;
}
sql += " ORDER BY timestamp ASC";
query.prepare(sql);
for (const QVariant &value : bindValues) {
query.addBindValue(value);
}
if (!query.exec()) {
qWarning() << "Query failed:" << query.lastError().text();
return results;
}
while (query.next()) {
QByteArray data = query.value("data").toByteArray();
results.append(data);
}
return results;
}
# 添加 PostgreSQL 支持
find_package(Qt6 REQUIRED COMPONENTS Core Sql)
target_link_libraries(soft_bus
Qt6::Core
Qt6::Sql
# PostgreSQL 客户端库(需要系统安装)
# libpq (PostgreSQL 客户端库)
)
是否需要分布式部署?
├─ 否 → 单机应用
│ ├─ 数据量是否很大(TB级别)?
│ │ ├─ 是 → RocksDB + SQLite 混合架构 ⭐
│ │ └─ 否 → SQLite 单独使用
│ └─ 资源是否受限?
│ ├─ 是 → RocksDB + SQLite 混合架构 ⭐
│ └─ 否 → SQLite 单独使用
│
└─ 是 → 分布式系统
├─ 是否需要时间序列优化?
│ ├─ 是 → PostgreSQL + TimescaleDB ⭐
│ └─ 否 → PostgreSQL 或 MySQL
└─ 团队是否熟悉?
├─ PostgreSQL → PostgreSQL + TimescaleDB ⭐
└─ MySQL → MySQL
对于您的 IoT 软总线系统:
您可以根据实际部署场景选择最适合的方案。