DolphinDB海量数据查询:分页与采样

目录

    • 摘要
    • 一、海量数据查询挑战
      • [1.1 海量数据查询问题](#1.1 海量数据查询问题)
      • [1.2 解决方案](#1.2 解决方案)
    • 二、分页查询
      • [2.1 LIMIT分页](#2.1 LIMIT分页)
      • [2.2 TOP分页](#2.2 TOP分页)
      • [2.3 分页函数](#2.3 分页函数)
      • [2.4 分布式表分页](#2.4 分布式表分页)
      • [2.5 分页最佳实践](#2.5 分页最佳实践)
    • 三、数据采样
      • [3.1 随机采样](#3.1 随机采样)
      • [3.2 系统采样](#3.2 系统采样)
      • [3.3 分层采样](#3.3 分层采样)
      • [3.4 时间采样](#3.4 时间采样)
      • [3.5 采样函数](#3.5 采样函数)
    • 四、结果缓存
      • [4.1 内存缓存](#4.1 内存缓存)
      • [4.2 共享表缓存](#4.2 共享表缓存)
      • [4.3 缓存更新策略](#4.3 缓存更新策略)
    • 五、异步查询
      • [5.1 异步查询原理](#5.1 异步查询原理)
      • [5.2 异步查询实现](#5.2 异步查询实现)
    • 六、查询优化技巧
      • [6.1 减少返回列](#6.1 减少返回列)
      • [6.2 使用分区条件](#6.2 使用分区条件)
      • [6.3 避免深分页](#6.3 避免深分页)
      • [6.4 分批处理](#6.4 分批处理)
    • 七、实战案例
      • [7.1 设备数据分页查询API](#7.1 设备数据分页查询API)
      • [7.2 数据采样分析](#7.2 数据采样分析)
    • 八、总结
    • 参考资料

摘要

本文深入讲解DolphinDB海量数据查询技术。从分页查询到数据采样,从结果缓存到查询优化,全面介绍处理海量数据的核心方法。通过丰富的代码示例,帮助读者掌握海量数据查询的核心技能。


一、海量数据查询挑战

1.1 海量数据查询问题

工业物联网场景下,数据量巨大,查询面临挑战:
海量数据查询挑战
数据量大
查询慢
结果集大
内存溢出
并发高
系统负载高
解决方案
分页查询
数据采样
结果缓存

1.2 解决方案

方案 说明 适用场景
分页查询 分批返回结果 列表展示
数据采样 采样部分数据 数据分析
结果缓存 缓存查询结果 重复查询
异步查询 异步执行查询 长时间查询

二、分页查询

2.1 LIMIT分页

python 复制代码
// 创建测试数据
t = table(
    1..10000 as id,
    2024.01.01 + 0..9999 as date,
    rand(20.0..30.0, 10000) as temperature,
    rand(40.0..60.0, 10000) as humidity
)

// 基本分页:每页100条
select * from t limit 100

// 分页查询:第2页(偏移100条)
select * from t limit 100 offset 100

// 分页查询:第3页
select * from t limit 100 offset 200

2.2 TOP分页

python 复制代码
// TOP分页:返回前N条
select top 100 * from t

// TOP分页带排序
select top 100 * from t order by id desc

2.3 分页函数

python 复制代码
// 分页查询函数
def paginateQuery(table, pageSize, pageNum) {
    offset = pageSize * (pageNum - 1)
    return select * from table limit pageSize offset offset
}

// 使用分页函数
t = table(
    1..10000 as id,
    rand(100.0, 10000) as value
)

// 第1页
paginateQuery(t, 100, 1)

// 第5页
paginateQuery(t, 100, 5)

// 第10页
paginateQuery(t, 100, 10)

2.4 分布式表分页

python 复制代码
// 创建分布式表
db = database("dfs://page_db", VALUE, 1..100)
schema = table(1:0, `device_id`timestamp`temperature`humidity,
               [INT, TIMESTAMP, DOUBLE, DOUBLE])
db.createPartitionedTable(schema, `sensor_data, `device_id)

// 插入数据
loadTable("dfs://page_db", "sensor_data").append!(
    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
    )
)

// 分布式表分页查询
t = loadTable("dfs://page_db", "sensor_data")

// 第1页
select * from t limit 100

// 第2页(注意:分布式表offset可能较慢)
select * from t limit 100 offset 100

// 优化:使用分区条件
select * from t 
where device_id = 1 
limit 100

2.5 分页最佳实践

实践 说明
使用分区条件 减少扫描数据量
避免大offset 大offset性能差
使用游标 替代大offset
限制页数 避免深分页

三、数据采样

3.1 随机采样

python 复制代码
// 创建测试数据
t = table(
    1..100000 as id,
    rand(100.0, 100000) as value
)

// 随机采样:采样10%
select * from t sample 0.1

// 随机采样:采样1000条
select * from t sample 1000

3.2 系统采样

python 复制代码
// 系统采样:每隔N条取一条
select * from t where id % 100 = 0

// 系统采样:每隔1000条取一条
select * from t where id % 1000 = 0

3.3 分层采样

python 复制代码
// 创建带分类的数据
t = table(
    take(1..10, 100000) as group_id,
    rand(100.0, 100000) as value
)

// 分层采样:每组采样100条
select * from (
    select *, row_number() over (partition by group_id order by rand()) as rn
    from t
) where rn <= 100

3.4 时间采样

python 复制代码
// 创建时间序列数据
t = table(
    2024.01.01T00:00:00 + 0..99999 * 60000 as timestamp,  // 每分钟
    rand(20.0..30.0, 100000) as temperature
)

// 时间采样:每小时取一条
select * from t where minute(timestamp) = 0

// 时间采样:使用bar函数
select bar(timestamp, 1h) as hour,
       first(temperature) as sample_temp
from t
group by bar(timestamp, 1h)

3.5 采样函数

python 复制代码
// 采样函数封装
def sampleData(table, sampleRate) {
    return select * from table sample sampleRate
}

def sampleByGroup(table, groupCol, sampleSize) {
    return select * from (
        select *, row_number() over (partition by groupCol order by rand()) as rn
        from table
    ) where rn <= sampleSize
}

// 使用采样函数
t = table(
    take(1..10, 10000) as group_id,
    rand(100.0, 10000) as value
)

// 随机采样10%
sampleData(t, 0.1)

// 分组采样:每组100条
sampleByGroup(t, `group_id, 100)

四、结果缓存

4.1 内存缓存

python 复制代码
// 查询结果缓存到内存
t = loadTable("dfs://page_db", "sensor_data")

// 执行查询并缓存
cachedResult = select device_id, avg(temperature) as avg_temp
               from t
               where date(timestamp) = 2024.01.15
               group by device_id

// 使用缓存结果
select * from cachedResult where avg_temp > 25

4.2 共享表缓存

python 复制代码
// 使用共享表缓存
share cachedResult as shared_cache

// 其他会话可以使用
select * from shared_cache

4.3 缓存更新策略

python 复制代码
// 定时更新缓存
def updateCache() {
    t = loadTable("dfs://page_db", "sensor_data")
    
    result = select device_id, avg(temperature) as avg_temp
             from t
             where date(timestamp) = today() - 1
             group by device_id
    
    // 更新共享缓存
    shared_cache = result
}

// 每日更新
scheduleJob("update_cache", "更新缓存", updateCache,
            01:00, 2024.01.01, 2030.12.31, 'D')

五、异步查询

5.1 异步查询原理

异步查询流程


提交查询
返回查询ID
后台执行
轮询状态
完成?
获取结果

5.2 异步查询实现

python 复制代码
// 异步查询函数
def asyncQuery(queryFunc) {
    // 提交查询
    jobId = submitJob("async_query", "异步查询", queryFunc)
    
    // 返回作业ID
    return jobId
}

// 查询作业状态
def checkQueryStatus(jobId) {
    return getJobStatus(jobId)
}

// 获取查询结果
def getQueryResult(jobId) {
    return getJobReturn(jobId)
}

// 使用异步查询
t = loadTable("dfs://page_db", "sensor_data")

// 提交异步查询
jobId = asyncQuery(def() {
    return select count(*) from loadTable("dfs://page_db", "sensor_data")
})

// 检查状态
checkQueryStatus(jobId)

// 获取结果
getQueryResult(jobId)

六、查询优化技巧

6.1 减少返回列

python 复制代码
// 不推荐:返回所有列
select * from t limit 1000

// 推荐:只返回需要的列
select id, temperature from t limit 1000

6.2 使用分区条件

python 复制代码
// 不推荐:全表扫描
select * from t limit 1000

// 推荐:分区裁剪
select * from t 
where device_id in 1..10
limit 1000

6.3 避免深分页

python 复制代码
// 不推荐:深分页(offset大)
select * from t limit 100 offset 100000

// 推荐:使用游标
select * from t 
where id > 100000  // 使用上一页最后一条的id
limit 100

6.4 分批处理

python 复制代码
// 分批处理大数据
def batchProcess(tableName, batchSize, processFunc) {
    t = loadTable(tableName)
    total = exec count(*) from t
    
    for (i in 0..(total \ batchSize)) {
        batch = select * from t limit batchSize offset i * batchSize
        processFunc(batch)
    }
}

// 使用分批处理
batchProcess("dfs://page_db/sensor_data", 10000, 
    def(batch) {
        // 处理每批数据
        print("处理批次: " + string(batch.rows()))
    })

七、实战案例

7.1 设备数据分页查询API

python 复制代码
// 设备数据分页查询API
def queryDeviceData(deviceId, startDate, endDate, pageSize, pageNum) {
    t = loadTable("dfs://page_db", "sensor_data")
    
    offset = pageSize * (pageNum - 1)
    
    // 查询总数
    total = exec count(*) from t 
            where device_id = deviceId
            and date(timestamp) between startDate and endDate
    
    // 分页查询
    data = select * from t
           where device_id = deviceId
           and date(timestamp) between startDate and endDate
           order by timestamp
           limit pageSize offset offset
    
    // 返回结果
    return dict(STRING, ANY, [
        ["total", total],
        ["pageSize", pageSize],
        ["pageNum", pageNum],
        ["totalPages", ceil(total / pageSize)],
        ["data", data]
    ])
}

// 使用API
result = queryDeviceData(1, 2024.01.01, 2024.01.31, 100, 1)
print("总数: " + string(result["total"]))
print("数据: ")
print(result["data"])

7.2 数据采样分析

python 复制代码
// 数据采样分析
def analyzeSampleData(sampleRate) {
    t = loadTable("dfs://page_db", "sensor_data")
    
    // 采样数据
    sample = select * from t sample sampleRate
    
    // 统计分析
    stats = select device_id,
                  count(*) as cnt,
                  avg(temperature) as avg_temp,
                  std(temperature) as std_temp
           from sample
           group by device_id
    
    return stats
}

// 使用采样分析
analyzeSampleData(0.01)  // 1%采样

八、总结

本文详细介绍了DolphinDB海量数据查询:

  1. 分页查询:LIMIT、TOP、分页函数
  2. 数据采样:随机采样、系统采样、分层采样
  3. 结果缓存:内存缓存、共享表缓存
  4. 异步查询:异步提交、状态检查、结果获取
  5. 查询优化:减少列、分区条件、避免深分页
  6. 实战应用:分页API、采样分析

思考题

  1. 如何优化深分页查询?
  2. 采样查询适合什么场景?
  3. 如何设计高效的分页API?

参考资料

相关推荐
七夜zippoe2 天前
DolphinDB多表关联查询:JOIN优化
优化·join·dolphindb·多表联查
七夜zippoe3 天前
DolphinDB时间序列查询:时间窗口与聚合
窗口·查询·时间序列·聚合·dolphindb
Xxtaoaooo3 天前
DolphinDB工业物联网实时分析:从海量数据困局到毫秒级预警的技术突围
物联网·struts·servlet·工业物联网·dolphindb
七夜zippoe4 天前
DolphinDB索引设计:提升查询性能
数据库·索引·性能·查询·dolphindb
七夜zippoe6 天前
DolphinDB查询优化:执行计划分析
大数据·数据库·信息可视化·dolphindb·查询优化
七夜zippoe7 天前
DolphinDB数据压缩与存储优化
优化·存储·数据·压缩·dolphindb
七夜zippoe8 天前
DolphinDB分区策略:HASH分区与COMPO分区
算法·哈希算法·hash·dolphindb·compo
七夜zippoe8 天前
DolphinDB分布式表:创建与管理
数据库·分布式·维度·dolphindb·数据写入
七夜zippoe10 天前
# DolphinDB分区策略:RANGE分区详解
数据库·策略·分区·range·dolphindb