DolphinDB 用户入门指南之金融篇(5)- 6. 基于 SQL 的批计算
本文页面提供《DolphinDB 用户入门指南之金融篇(5)》的标题、作者与发布日期等基础信息。
Source: https://dolphindb.cn/blogs/140
What this page covers
- 库表加载与分布式表访问方式。
- SQL where 条件触发分区剪枝的写法对比与观察方法。
- TSDB 的 sortColumns 索引与单点查询加速思路。
- 聚合计算与 K 线合成示例(含缺失填充与分区串行计算)。
- 时序分析示例:SOIR 因子定义与脚本实现。
- 截面计算:pivot / 面板数据与排名计算。
- 常见问题:去重写入、查询优化、分布式优化与元数据等。
技能认证特训营第二期报名促销 (cta)
页面顶部提供活动报名入口,并提及限时报名福利信息。
- 该活动描述为“正式开启(限时报名,享专属福利优惠)”。
- 页面提供一个限时报名链接。
DolphinDB 用户入门指南之金融篇(5) (hero)
本节呈现文章基础信息,包括标题、作者与发布日期。
- 作者署名为 momo。
- 发布日期为 2025-01-07。
- 文章标题包含“6. 基于 SQL 的批计算”。
6. 基于 SQL 的批计算(章节导语) (definition)
本章说明将涵盖基于 SQL 的数据处理主题,并声明示例基于指定库表。
- 示例数据来源为库 dfs://stock_lv2_snapshot 下的快照表 snapshot。
- 本章围绕 SQL 的批计算主题展开。
6.1 库表加载 (how_it_works)
本节介绍加载与访问分布式表的多种方式,并说明 loadTable 的句柄加载语义。
- 可使用 database 函数加载已创建的库表(示例:snapdb = database("dfs://stock_lv2_snapshot"))。
- 可用 use catalog xxx 加载数据目录并查询(示例:use catalog trading)。
- 可用 loadTable(dbName, tbName) 加载分布式表句柄并查询。
- 可通过“数据库句柄"."表名"访问分布式表(示例:snapdb.snapshot)。
- loadTable 加载的是分布式表句柄(元数据信息)。
- 对句柄进行查询时,数据才真正加载到内存。
6.2 分区剪枝 (how_it_works)
本节说明 SQL 查询/更新/删除可基于 where 条件触发分区剪枝,并用 HINT_EXPLAIN 对比不同条件写法的效果。
- SQL 查询、更新和删除可根据 where 条件进行分区剪枝以减少扫描分区数。
- HINT_EXPLAIN 可用于打印执行计划以观察是否进行剪枝。
- 分区剪枝触发示例包括 between 语句与非链式过滤条件。
- 链式条件过滤示例(2022.12.01 <= TradeDate <= 2022.12.03)不触发分区剪枝。
- 示例中,TradeDate between 2022.12.01 and 2022.12.03 的 partitions.localScanned 为 90。
- 示例中,链式条件的 partitions.localScanned 为 10891。
- 示例中,等值查询(SecurityID="000001")的 partitions.localScanned 为 243。
- 示例中,IN 查询(SecurityID in ["000001","000002"])的 partitions.localScanned 为 485。
- 示例中,时间函数条件(month(TradeDate)=2022.02M 且 SecurityID="000001")的 partitions.localScanned 为 16。
6.3 单点查询(TSDB 索引加速) (how_it_works)
本节说明 TSDB 通过 sortColumns 维护键值索引以加速查询,并展示如何查看索引配置与观察索引命中。
- TSDB 引擎会额外维护键值索引(由配置参数 sortColumns 指定)以加速查询。
- 示例中,schema(...).sortColumns 输出为 ["SecurityID","TradeTime"]。
- 示例解释中,索引键由除最后一个时间列外的字段构成(例:SecurityID)。
- 示例解释中,每个索引对应的数据按 TradeTime 顺序存储在磁盘上。
- 示例表中,SecurityID 既是分区列又是索引键。
- 索引命中示例中,blocksToBeScanned 为 62。
- 索引命中示例中,matchedWhereConditions 为 1。
6.4 聚合计算(K 线合成示例) (how_it_works)
本节介绍金融聚合的常见方式,并通过示例演示 OHLC 与分钟 K 线合成、缺失填充及分区串行计算方案。
- 金融场景聚合计算常见维度包括按交易时间与按股票标的。
- 示例使用 group by symbol 与 bar(time, ...) 进行 5 分钟 OHLC 聚合。
- bar 函数用于按时间划分分组(示例:每 5 分钟一组)。
- 分钟 K 线合成示例目标包含:某分钟无数据时填充为 0。
- 预处理规则:将 09:25:00-09:30:00 数据归入第一根 K 线 [09:30:00, 09:31:00]。
- 窗口设置:对处理后的快照行情做 1 分钟窗口、1 分钟步长的滚动窗口计算。
- interval 函数必须与 group by 语句搭配使用。
- 示例中,interval 将毫秒精度时间字段按分钟窗口划分,并设置 fill=0。
- 社区版 server 直接执行分钟 K 线示例可能出现 Out of memory 风险。
- 替代方案:按分区串行计算后合并结果,并用 mr(parallel=false) 执行。
- 示例将计算逻辑封装为函数 calcKLine。
- sqlDS 可根据指定 SQL 查询筛选数据,并按分区生成数据源列表。
6.5 时序分析(SOIR 因子示例) (use_case)
本节讨论金融时序分析用途,并以 SOIR 因子为例给出定义、脚本实现与相关参数信息。
- DolphinDB 提供滑动窗口、累积窗口与序列计算等内置函数。
- DolphinDB 提供 Talib、MyTT 算子指标库与 Alpha 因子库等模块。
- SOIR 因子用于衡量买卖委托量在总量中的不均衡程度。
- 示例实现使用 rowWavg 计算前 10 档加权平均的买卖委托量不均衡程度。
- 示例实现使用 moving 系列函数进行移动标准化处理。
- wavgSOIR 函数默认参数 lag 为 20。
6.6 截面计算(pivot / 面板数据) (how_it_works)
本节解释截面比较需要将窄表转换为面板数据,并通过 pivot by 与相关函数展示转换结果与排名计算。
- 截面计算需要将窄表进行行列转换以转成面板数据。
- DolphinDB SQL 语义拓展提供 pivot by 语句。
- DolphinDB 提供用于内存计算的 pivot 与 panel 函数。
- exec + pivot by 可将表转换为面板矩阵。
- 面板矩阵的行列标签记录面板数据的维度信息。
- 示例矩阵类型为 FAST DOUBLE MATRIX。
- 示例矩阵列名为 ["C","IBM","MS"]。
- 示例矩阵行名包含 09:34:07、09:34:16、09:35:26 等时间标签。
- 截面排名示例:先 pivot(按 TradeDate 与 SecurityID),再对行做 rowRank。
6.7 常见问题 (faq)
本节以问答形式汇总去重写入、查询与分布式优化、脚本组织、表操作与 TSDB/分区元数据相关问题。
- 去重写入方法之一:利用 TSDB 的 sortColumns 去重。
- sortColumns 去重不适用于每个索引键数据量很少的场景(可能索引膨胀)。
- 去重写入方法之一:使用 upsert! 并设置 keyColNames。
- 查询优化检查点包括:是否触发分区剪枝与是否走分布式查询优化。
- 若未通过 mapr 关键字声明,自定义函数无法进行分布式查询优化。
- 计算不跨分区时,可在查询语句后添加 map。
- 计算跨分区时,可用 mr 定义 map/reduce/final 分布式计算逻辑。
- 字段多时可用元编程或字段序列定义脚本。
- 表关联结果会将两边公共列拆成两列返回(示例 fj)。
- 合并公共列示例:使用 nullFill 合并两侧 id 字段。
- dropTable 用于删除分布式表。
- 共享内存表可用 undef("st", SHARED) 删除。
- 分布式表 update/delete 开销大与按分区读写有关。
- TSDB keepDuplicates=LAST 时,更新可采用追加方式进行。
- TSDB keepDuplicates=LAST 且 softDelete=true 时,可进行软删除并追加写回。
- 示例对比:获取日期唯一值的 timeElapsed 出现多种方案结果。
- 示例解释:通过解析分区元数据获取日期信息可获得较佳性能表现。
- TSDB zonemap 元数据包含每列每个 sortKey 的预聚合信息(min/max/sum/notnullcount 等)。
- 文中描述:当查询包含预聚合指标且 keepDuplicates=ALL 时,可利用 zonemap 提速。
- 可通过 HINT_EXPLAIN 观察过滤条件是否命中索引(matchedWhereConditions 等字段)。
6.8 下一步阅读 (navigation)
本节提供与分区剪枝、SQL 执行计划、聚合/时序/面板数据处理相关的进一步阅读链接。
- 包含与分区剪枝相关的进一步阅读入口。
- 包含与 SQL 执行计划相关的进一步阅读入口。
- 包含与聚合计算、时序计算与面板数据处理相关的进一步阅读入口。
Facts index
| Entity | Attribute | Value | Confidence |
|---|---|---|---|
| DolphinDB 用户入门指南之金融篇(5) | publish_date | 2025-01-07 | high |
| 文章作者 | name | momo | high |
| 技能认证特训营第二期 | status | 正式开启(限时报名,享专属福利优惠) | low |
| 限时报名链接 | url | https://www.qingsuyun.com/h5/e/217471/5/ | high |
| 本章示例数据来源 | dataset | 基于 3.3 节创建的 "dfs://stock_lv2_snapshot" 库下快照表 snapshot | high |
| DolphinDB | load_database_method | 可用 database 函数加载已创建的库表(示例:snapdb = database("dfs://stock_lv2_snapshot")) | high |
| DolphinDB 数据目录 | load_method | 可用 "use catalog xxx" 加载对应数据目录并查询(示例:use catalog trading;select count(*) from stock_lv2_snapshot.snapshot) | high |
| DolphinDB | load_distributed_table_method | 可用 loadTable(dbName, tbName) 加载分布式表句柄并查询 | high |
| DolphinDB | distributed_table_access | 可通过 "数据库句柄"."表名" 访问分布式表(示例:snapdb.snapshot) | high |
| loadTable | loading_semantics | loadTable 加载的是分布式表句柄(元数据信息);只有对句柄查询时才真正将数据加载到内存 | high |
| DolphinDB | partition_pruning_support | 在 SQL 查询、更新和删除时可根据 where 条件(包含分区字段)进行分区剪枝以减少扫描分区数 | high |
| HINT_EXPLAIN | purpose | 用于打印执行计划以观察是否进行剪枝 | high |
| 分区剪枝示例(TradeDate between 2022.12.01 and 2022.12.03) | partitions_local_scanned | 90 | high |
| 链式条件示例(2022.12.01 <= TradeDate <= 2022.12.03) | partitions_local_scanned | 10891 | high |
| 分区剪枝触发条件示例 | works_with | between 语句、非链式过滤条件 | high |
| 分区剪枝不触发条件示例 | does_not_work_with | 链式条件过滤(示例:2022.12.01 <= TradeDate <= 2022.12.03) | high |
| 等值查询剪枝示例(SecurityID = "000001") | partitions_local_scanned | 243 | high |
| IN 查询剪枝示例(SecurityID in ["000001","000002"]) | partitions_local_scanned | 485 | high |
| 时间函数剪枝示例(month(TradeDate)=2022.02M and SecurityID="000001") | partitions_local_scanned | 16 | high |
| TSDB 引擎 | index_type | 额外维护键值索引(由配置参数 sortColumns 指定)以加速查询 | high |
| schema(...).sortColumns | example_output | ["SecurityID","TradeTime"] | high |
| TSDB sortColumns 含义(示例解释) | index_key_and_order | 索引键为 SecurityID(除最后一个时间列外字段构成索引键),且每个索引对应的数据按 TradeTime 顺序存储在磁盘上 | high |
| SecurityID 字段(示例表) | role_in_query_optimization | 既是分区列又是索引键;包含 SecurityID 的查询条件既可分区剪枝也可借助内存索引快速定位数据块 | high |
| TSDB 索引命中示例(TradeDate=2022.12.01 and SecurityID="000002") | blocksToBeScanned | 62 | high |
| TSDB 索引命中示例(TradeDate=2022.12.01 and SecurityID="000002") | matchedWhereConditions | 1 | high |
| 聚合计算(金融场景) | common_aggregation_axes | 按交易时间聚合;按股票标的聚合 | high |
| OHLC 示例(5分钟K线) | grouping_method | select first/max/min/last/sum from trade group by symbol, date, bar(time, barMinutes*60*1000) as barStart | high |
| bar 函数(示例语义) | purpose | 按时间将每 5 分钟数据划分为一组(用于 group by 时间窗口) | high |
| 分钟K线合成示例目标 | missing_minute_handling | 若某只股票在某一分钟无数据,则填充为 0 | high |
| 分钟K线数据预处理规则 | rule | 将 09:25:00-09:30:00 的数据归入第一根K线 [09:30:00, 09:31:00] | high |
| 分钟K线计算(窗口设置) | window | 对处理后的快照行情进行窗口为 1 分钟、步长为 1 分钟的滚动窗口计算 | high |
| interval 函数(示例) | usage_constraints | interval 函数必须与 group by 语句搭配使用 | high |
| interval 函数(示例效果) | value | 将毫秒精度时间字段按分钟窗口划分,缺失值填充为 0(fill=0) | high |
| 社区版 server 执行分钟K线示例 | risk | 快照表 snapshot 数据量很大,直接执行可能报错 Out of memory | high |
| 替代计算方案(分钟K线) | approach | 按分区串行计算然后合并结果;将计算逻辑封装为函数 calcKLine,并用 mr(parallel=false) 执行 | high |
| sqlDS(示例用途) | purpose | 根据指定 SQL 查询筛选数据,并按分区生成数据源列表 | high |
| 时序分析(DolphinDB 能力) | capabilities | 提供滑动窗口、累积窗口、序列计算等内置函数,以及 Talib、MyTT 算子指标库和 Alpha 因子库等模块 | medium |
| SOIR 因子 | purpose | 衡量买卖委托量在总量中的不均衡程度 | high |
| SOIR 脚本实现 | method | 使用 rowWavg 计算前10档加权平均的买卖委托量不均衡程度,并用 moving 系列函数进行移动标准化处理 | high |
| wavgSOIR 函数默认参数 | lag_default | 20 | high |
| 截面计算 | need | 需要将窄表进行行列转换以转成面板数据,用于同一时间截面不同股票比较/计算 | high |
| DolphinDB SQL 语义拓展 | pivot_support | 提供 pivot by 语句,并开发用于内存计算的 pivot、panel 函数 | high |
| exec + pivot by(示例) | result_type | 将表转换成面板矩阵,行列标签记录面板数据的维度信息 | high |
| pivot 示例矩阵类型 | typestr | FAST DOUBLE MATRIX | high |
| pivot 示例矩阵列名 | colNames | ["C","IBM","MS"] | high |
| pivot 示例矩阵行名 | rowNames | [09:34:07,09:34:16,09:35:26,09:35:42,09:35:47,09:36:12,09:36:26,09:36:51,09:36:59] | high |
| 截面排名示例 | calculation | 按 TradeDate 与 SecurityID 做 pivot(m = exec last(LastPrice) ... pivot by TradeDate, SecurityID),再对行做 rowRank(m) | high |
| 分布式表写入去重(FAQ) | method_1 | TSDB 引擎 sortColumns 去重:系统根据 sortColumns 去重;不适用于每个索引键对应数据量很少的场景,可能造成索引膨胀影响查询效率 | high |
| 分布式表写入去重(FAQ) | method_2 | 使用 upsert! 写入并设置 keyColNames;写入时检查数据键存在则更新否则追加,以达到去重目的 | high |
| 查询性能优化(FAQ) | checklist | 是否触发分区剪枝(where 条件改写);是否走分布式查询优化(自定义函数可用 mr 改写) | high |
| 自定义函数分布式优化(FAQ) | condition | 若未通过 mapr 关键字声明,则自定义函数无法进行分布式查询优化 | high |
| map 关键字(FAQ) | use_case | 计算数据不跨分区时,在查询语句后添加 map(示例:select first(id), count(*) from pt map) | high |
| mr 函数(FAQ) | distributed_model | 计算跨分区时通过 mr 定义分布式计算逻辑:mapFunc 映射到各分区执行,reduceFunc 汇总,finalFunc 做最后计算 | high |
| 代码优化(FAQ) | approach | 字段多可用元编程或字段序列定义脚本;字段序列限制较多,元编程适用范围更广 | high |
| 表关联结果(FAQ) | behavior | 表关联结果会将两边公共列拆成两列返回(示例 fj 返回 id 与 t2_id) | high |
| 合并公共列(FAQ) | solution | select t1.id.nullFill(t2.id) as id, value, qty from fj(t1, t2, `id) | high |
| dropTable(FAQ) | scope | dropTable 用于删除分布式表;共享内存表可用 undef("st", SHARED) 删除 | high |
| update/delete 事务开销大原因(FAQ) | reason | 分布式数据按列式(OLAP)或行列混存(TSDB);行级更新/删除会按分区读出相关字段到内存更新/删除再写回磁盘;分区多或数据量大则开销大 | high |
| TSDB 更新/删除优化(FAQ) | optimization_1 | keepDuplicates=LAST 时,数据更新以追加方式进行 | high |
| TSDB 删除优化(FAQ) | optimization_2 | keepDuplicates=LAST 且 softDelete=true 时,删除为软删除:打删除标记后以追加方式写回数据库 | high |
| snapshot 表元数据(示例) | engineType | TSDB | high |
| snapshot 表元数据(示例) | keepDuplicates | ALL | high |
| snapshot 表元数据(示例) | chunkGranularity | TABLE | high |
| snapshot 表元数据(示例) | sortColumns | ["SecurityID","TradeTime"] | high |
| snapshot 表元数据(示例) | softDelete | 0 | high |
| snapshot 表元数据(示例) | partitionColumnName | ["TradeDate","SecurityID"] | high |
| snapshot 表元数据(示例) | partitionTypeName | ["VALUE","HASH"] | high |
| 获取日期唯一值(示例对比) | time_elapsed_distinct | 670.988 ms | high |
| 获取日期唯一值(示例对比) | time_elapsed_group_by | 373.783 ms | high |
| 获取日期唯一值(示例对比) | time_elapsed_metadata_parse | 35.623 ms | high |
| 日期唯一值方案 3 性能原因(示例) | explanation | 通过直接解析分区元数据获取日期信息,因此性能最佳 | high |
| VALUE 分区自动拓展(示例说明) | implication | 若建库 VALUE 分区方案包含在数据范围内,可通过 schema(pt).partitionSchema[0] 获取日期分区字段值;示例得到长度 244 向量且包含 2024.01.01 与 2024.01.02(虽无数据)因其被建库方案纳入元数据 | high |
| TSDB zonemap 元数据(FAQ 示例 2) | contains | 每列每个 sortKey 对应数据的 min、max、sum、notnullcount 等预聚合信息 | high |
| zonemap 提速条件(FAQ 示例 2) | conditions | 查询包含 count/min/max/sum 等预聚合指标,且使用 keepDuplicates=ALL 时可利用 zonemap 提速(文中描述) | medium |
| TSDB sortKey 索引命中观察(FAQ 示例 3) | method | 可通过 HINT_EXPLAIN 执行计划观察过滤条件是否命中索引(matchedWhereConditions 等字段) | high |