Skip to main content

本指南旨在帮助数据组同学在 3 分钟内掌握 blockdb-py SDK 的核心使用方法。通过本 SDK,你可以直接在 Notebook 或本地脚本中以纯 Python 原生对象操作 BlockDB,平台全域只暴露 SDK API,不暴露原始 SQL。

3 分钟极速热身

在 Chaintable 中,无论是普通在线表(L1)还是区块链特化表(L2),其核心开发范式均为:「通过构造器传入表名创建实例 -> 调用语义化方法」。所有查询方法均返回标准的 Python dictlist[dict],可直接无缝喂给 pandas.DataFrame
from blockdb import Table

# 1) 构造一个指向具体 table_id 的 L1(行级)普通在线表实例
events = Table("demo.event_log")

# 2) 按业务主键快速读取单行;记录不存在时返回 None
row = events.get_row("evt_001")
print(f"Row data: {row}")

# 3) 批量读取多个主键(生产环境强烈推荐,单次 RPC 效率极高)
rows = events.batch_get_rows(["evt_001", "evt_002", "evt_003"])


核心数据业务场景 Cookbook

场景 1 — 全表扫描与大规模条件检索 (L1 表)

日常分析中,当你需要从一张大规模 L1 在线表中捞取特定条件的数据时,SDK 提供了两套依据数据量级分流的精准”姿势”:
from blockdb import Table
events = Table("demo.event_log")

# 姿势 A:条件简单、结果集行数可控(≤ 10万行) -> 一次性拿回 list
hits = events.filter_rows(
    filters="created_at >= 1700000000 AND name IN ('login', 'signup')",
    order_by="created_at asc",
    limit=200,
)

# 姿势 B:结果集极其庞大(百万/千万级) -> 流式逐行 yield,内存保持恒定 O(1)
# 警告:不要用 list(events.scan_iter(...)) 强转,否则会导致内存撑爆(OOM)
for row in events.scan_iter("SELECT * FROM demo.event_log WHERE name = 'login'"):
    # row 为单行 dict,可在此处进行增量过滤或写出
    pass

  • 最佳实践:大表(>10万行)检索必须走 scan_iter。另外,传入的 SQL 字符串**结尾绝不能带有分号 ;**,系统不支持多条 SQL 拼接执行。

场景 2 — 物理时序状态查询与级联写入 (TimeTable)

针对随物理挂钟时间(而非区块高度)动态变化的指标(如:代币分钟喂价、每分钟 TVL 快照),BlockDB 提供了特化的 TimeTable,其时间桶固定为 60 秒

核心特性:向后取整,秒归零

不管你传入的业务时间是 17:04:35 还是 17:04:59,SDK 内部在读写时都会自动将其进位并归到 17:05:00 这个固定的分钟桶。这确保了分布式计算下,所有端到端的读写口径天然对齐。
from blockdb import TimeTable
from blockdb.time_table import align_time_at

t = TimeTable("analytics.token_price_1m")

# 1) 写:往特定时间桶批量 Upsert(传 17:04:35 会自动进位到 17:05:00)
job_id = t.upsert_time_rows(
    "2026-05-18 17:04:35",
    [{"id": "0xabc...", "value": 123.456}],
    sync=True
)

# 2) 读:计算场景下,强烈建议使用 L2 的 get_value() 获取具备分钟对齐、历史回溯能力的状态
# 避坑:直接去查 L1 物理表只能拿到最新瞬时值,无法享受时间桶和历史版本压缩的红利
row = t.get_value("0xabc...", "2026-05-18 17:04:40") 
# 返回 -> {"id": "0xabc...", "value": 123.456, "time_at": "2026-05-18 17:05:00"}

  • 手动回填后门:如果需要补录大量的历史时序数据,可以通过 L1 普通表的 upsert_rows 接口直接灌入物理底层,TimeTable 的后台引擎会自动触发异步计算,将历史快照重算并刷新到 latest 视图中。

高阶参数与性能调优白皮书

1. 写入权衡:sync=True vs sync=False

所有写入方法(upsert_rows, delete_rows 等)均支持 sync 参数控制行为:
  • sync=True(默认):等待 BlockDB 服务端物理落盘并确认后再返回。慢,但具备强一致性。 适用于单测、交互式分析、或下一步紧接着要读取该结果的依赖任务。
  • sync=False:Fire-and-forget(触发即忘),提交完立刻拿 job_id 返回,由后台异步处理。极快,吞吐量爆炸。 适用于大规模历史区块清洗和百万级批回填。

2. 读写黄金定律

  • 杜绝 For 循环点查:需要查询 NN 个主键时,**永远使用 batch_get_rows([...])**,严禁在 for 循环中重复调用 get_row()。一次批量 RPC 与 NN 次独立 RPC 的时延差距可达数个数量级。

沙箱 Debug 模式(写入意图预演)

为了防止处于联调期的实验脚本往生产环境脏写数据,SDK 内置了只影响写入操作的 Debug 熔断开关。

如何开启

可以通过配置系统环境变量(推荐,支持 GitOps 统一管控)或在代码运行时强行切换:
export BLOCKDB_DEBUG=1  # 1 / true / yes / on 均可触发开启

from blockdb._grpc_client import debug
debug.set_debug(True)  # 运行时强制开启

行为特征

开启后,任何写入函数均不会对 BlockDB 的实际物理数据产生任何修改。
  • 读操作(如 get_row, scan)照常执行,读取真实生产数据。
  • 所有写入操作全部被拦截,并固定返回 job_id = "debug-job"
  • 写入的真实内容(操作表名、行数、前 10 行样例)会被序列化为标准 JSON,转发给平台的日志展示系统。允许你在正式跑数前,肉眼自检”我究竟会往数据库里写进什么”。