目录
-
- 摘要
- 一、查询优化概述
-
- [1.1 为什么需要查询优化](#1.1 为什么需要查询优化)
- [1.2 DolphinDB查询优化特点](#1.2 DolphinDB查询优化特点)
- [1.3 查询优化流程](#1.3 查询优化流程)
- 二、执行计划分析
-
- [2.1 查看执行计划](#2.1 查看执行计划)
- [2.2 执行计划解读](#2.2 执行计划解读)
- [2.3 性能分析](#2.3 性能分析)
- 三、分区裁剪优化
-
- [3.1 分区裁剪原理](#3.1 分区裁剪原理)
- [3.2 分区裁剪示例](#3.2 分区裁剪示例)
- [3.3 分区裁剪优化](#3.3 分区裁剪优化)
- 四、索引优化
-
- [4.1 索引类型](#4.1 索引类型)
- [4.2 创建索引](#4.2 创建索引)
- [4.3 索引使用分析](#4.3 索引使用分析)
- 五、查询重写优化
-
- [5.1 避免SELECT *](#5.1 避免SELECT *)
- [5.2 使用LIMIT](#5.2 使用LIMIT)
- [5.3 避免复杂子查询](#5.3 避免复杂子查询)
- [5.4 使用WITH子句](#5.4 使用WITH子句)
- 六、聚合查询优化
-
- [6.1 分组优化](#6.1 分组优化)
- [6.2 窗口函数优化](#6.2 窗口函数优化)
- 七、分布式查询优化
-
- [7.1 分布式查询原理](#7.1 分布式查询原理)
- [7.2 分布式聚合](#7.2 分布式聚合)
- [7.3 分布式JOIN](#7.3 分布式JOIN)
- 八、查询优化最佳实践
-
- [8.1 优化清单](#8.1 优化清单)
- [8.2 性能监控](#8.2 性能监控)
- 九、总结
- 参考资料
摘要
本文深入讲解DolphinDB查询优化技术。从执行计划分析到性能诊断,从索引使用到分区裁剪,从查询重写到最佳实践,全面介绍如何提升查询性能。通过丰富的代码示例,帮助读者掌握查询优化的核心技能。
一、查询优化概述
1.1 为什么需要查询优化
工业物联网场景下,数据量巨大,查询性能直接影响业务效率:
查询优化价值
慢查询
10秒
优化后
0.1秒
用户体验提升
系统负载降低
成本节约
1.2 DolphinDB查询优化特点
| 特点 | 说明 |
|---|---|
| 分区裁剪 | 自动过滤无关分区 |
| 列裁剪 | 只读取需要的列 |
| 索引优化 | 支持多种索引 |
| 向量化执行 | 批量计算加速 |
1.3 查询优化流程
SQL语句
解析
优化
执行
返回结果
分区裁剪
索引选择
执行计划
二、执行计划分析
2.1 查看执行计划
python
// 创建测试表
db = database("dfs://test_db", VALUE, 1..100)
schema = table(1:0, `device_id`timestamp`temperature`humidity,
[INT, TIMESTAMP, DOUBLE, DOUBLE])
db.createPartitionedTable(schema, `sensor_data, `device_id)
// 插入测试数据
t = table(
take(1..100, 100000) as device_id,
take(now(), 100000) as timestamp,
rand(20.0..30.0, 100000) as temperature,
rand(40.0..60.0, 100000) as humidity
)
loadTable("dfs://test_db", "sensor_data").append!(t)
// 查看执行计划
t = loadTable("dfs://test_db", "sensor_data")
explain select * from t where device_id = 1
2.2 执行计划解读
python
// 执行计划输出示例
/*
+--------------------------------------------------+
| Execution Plan |
+--------------------------------------------------+
| TableScan: dfs://test_db/sensor_data |
| Partition Filter: device_id = 1 |
| Columns: device_id, timestamp, temperature... |
| Estimated Rows: 1000 |
+--------------------------------------------------+
*/
// 关键指标:
// 1. TableScan: 表扫描方式
// 2. Partition Filter: 分区过滤条件
// 3. Columns: 读取的列
// 4. Estimated Rows: 预估行数
2.3 性能分析
python
// 使用timer测量查询时间
timer select count(*) from t where device_id = 1
// 使用timer详细分析
timer {
result = select count(*) from t where device_id = 1
print("查询结果: " + string(result))
}
三、分区裁剪优化
3.1 分区裁剪原理
分区裁剪
是
否
查询条件
分区列过滤
只扫描相关分区
扫描所有分区
查询快
查询慢
3.2 分区裁剪示例
python
// 创建分区表
db = database("dfs://partition_db", COMPO,
[RANGE, 2024.01.01..2024.12.31,
VALUE, 1..100])
schema = table(1:0, `device_id`timestamp`temperature`humidity,
[INT, TIMESTAMP, DOUBLE, DOUBLE])
db.createPartitionedTable(schema, `sensor_data, `timestamp`device_id)
t = loadTable("dfs://partition_db", "sensor_data")
// 查询1:分区裁剪(快)
timer select count(*) from t
where date(timestamp) = 2024.01.15 and device_id = 50
// 查询2:部分分区裁剪(中)
timer select count(*) from t
where date(timestamp) = 2024.01.15
// 查询3:无分区裁剪(慢)
timer select count(*) from t
where temperature > 25
3.3 分区裁剪优化
python
// 优化前:无分区裁剪
select * from t where temperature > 25
// 优化后:添加分区条件
select * from t
where date(timestamp) between 2024.01.01 and 2024.01.31
and temperature > 25
四、索引优化
4.1 索引类型
| 索引类型 | 说明 | 适用场景 |
|---|---|---|
| 分区索引 | 分区列自动索引 | 分区查询 |
| 排序列索引 | 排序列索引 | 范围查询 |
| 位图索引 | 位图索引 | 低基数列 |
4.2 创建索引
python
// 创建带排序列的表
db = database("dfs://index_db", VALUE, 1..100)
schema = table(1:0, `device_id`timestamp`temperature`humidity,
[INT, TIMESTAMP, DOUBLE, DOUBLE])
db.createPartitionedTable(schema, `sensor_data, `device_id, `timestamp)
// 排序列自动创建索引
// 查询时可以利用排序索引加速
t = loadTable("dfs://index_db", "sensor_data")
// 范围查询利用排序索引
select * from t
where device_id = 1
and timestamp between 2024.01.01T00:00:00 and 2024.01.01T01:00:00
4.3 索引使用分析
python
// 查看索引使用情况
explain select * from t
where device_id = 1
and timestamp between 2024.01.01T00:00:00 and 2024.01.01T01:00:00
// 索引失效场景
// 1. 函数包装索引列
select * from t where year(timestamp) = 2024 // 索引失效
// 2. 类型转换
select * from t where string(device_id) = "1" // 索引失效
// 3. 计算表达式
select * from t where device_id + 1 = 2 // 索引失效
五、查询重写优化
5.1 避免SELECT *
python
// 不推荐:SELECT *
select * from t where device_id = 1
// 推荐:只查询需要的列
select device_id, timestamp, temperature
from t
where device_id = 1
5.2 使用LIMIT
python
// 不推荐:返回大量数据
select * from t where device_id = 1
// 推荐:限制返回行数
select top 100 * from t where device_id = 1
// 分页查询
select * from t where device_id = 1 limit 100 offset 0
5.3 避免复杂子查询
python
// 不推荐:复杂子查询
select * from t1
where device_id in (
select device_id from t2 where status = 'active'
)
// 推荐:使用JOIN
select t1.*
from t1
inner join t2 on t1.device_id = t2.device_id
where t2.status = 'active'
5.4 使用WITH子句
python
// 不推荐:重复子查询
select * from (
select device_id, avg(temperature) as avg_temp
from t group by device_id
) where avg_temp > 25
// 推荐:使用WITH子句
with device_stats as (
select device_id, avg(temperature) as avg_temp
from t group by device_id
)
select * from device_stats where avg_temp > 25
六、聚合查询优化
6.1 分组优化
python
// 创建测试数据
t = table(
take(1..100, 1000000) as device_id,
take(2024.01.01 + 0..99, 1000000) as date,
rand(20.0..30.0, 1000000) as temperature
)
// 优化前:大分组
timer select device_id, avg(temperature)
from t group by device_id
// 优化后:小分组(先过滤)
timer select device_id, avg(temperature)
from t
where date between 2024.01.01 and 2024.01.31
group by device_id
6.2 窗口函数优化
python
// 窗口函数优化
select device_id, timestamp, temperature,
avg(temperature) over (
partition by device_id
order by timestamp
rows between 100 preceding and current row
) as moving_avg
from t
where device_id in 1..10 // 先过滤再计算
七、分布式查询优化
7.1 分布式查询原理
分布式查询
客户端
Coordinator
Node1
Node2
Node3
局部结果1
局部结果2
局部结果3
合并结果
7.2 分布式聚合
python
// 分布式聚合自动并行
t = loadTable("dfs://partition_db", "sensor_data")
// 自动分布式执行
select device_id, avg(temperature) as avg_temp
from t
group by device_id
// 查看分布式执行计划
explain select device_id, avg(temperature)
from t group by device_id
7.3 分布式JOIN
python
// 创建两个分布式表
db = database("dfs://join_db", VALUE, 1..100)
schema1 = table(1:0, `device_id`timestamp`temperature,
[INT, TIMESTAMP, DOUBLE])
db.createPartitionedTable(schema1, `sensor_data, `device_id)
schema2 = table(1:0, `device_id`device_name`location,
[INT, STRING, STRING])
db.createTable(schema2, `device_info)
// 分布式JOIN
select s.device_id, s.temperature, d.device_name, d.location
from loadTable("dfs://join_db", "sensor_data") s
inner join loadTable("dfs://join_db", "device_info") d
on s.device_id = d.device_id
八、查询优化最佳实践
8.1 优化清单
| 优化项 | 说明 |
|---|---|
| 分区裁剪 | 在分区列上过滤 |
| 列裁剪 | 只查询需要的列 |
| 索引使用 | 利用索引加速 |
| 限制结果 | 使用LIMIT |
| 避免全表 | 添加WHERE条件 |
| 合理分组 | 先过滤再分组 |
8.2 性能监控
python
// 查询性能监控
def monitorQuery(query) {
start = now()
result = query()
end = now()
print("查询耗时: " + string(end - start) + "ms")
print("返回行数: " + string(result.rows()))
return result
}
// 使用监控
monitorQuery(def() {
select count(*) from loadTable("dfs://test_db", "sensor_data")
})
九、总结
本文详细介绍了DolphinDB查询优化技术:
- 执行计划:查看计划、解读计划、性能分析
- 分区裁剪:裁剪原理、裁剪示例、优化方法
- 索引优化:索引类型、创建索引、索引使用
- 查询重写:避免SELECT *、使用LIMIT、优化子查询
- 聚合优化:分组优化、窗口函数优化
- 分布式查询:分布式聚合、分布式JOIN
思考题:
- 如何分析慢查询?
- 分区裁剪如何提升查询性能?
- 如何选择合适的索引?