> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blockdb.chaintable.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Time 表

> 了解 Time 表：按物理时间分桶的序列表，内置去重与存储压缩。

# Time 表

Time 表是 BlockDB 的一种业务抽象表，描述**某个对象随物理（挂钟）时间变化的状态序列**，例如 token 的美元价格、每分钟的 TVL 快照。它与 Block State / Block Event 表（区块维度）并列，解决的是"某个对象随时间怎么变"的问题。

## 业务场景

Time 表适合任何随物理时间变化、与区块高度无关的指标：

* token 每分钟的美元价格。
* 每分钟 / 每小时的 TVL 快照。
* 用户在某段时间的持仓或持仓价值曲线。

## 表结构

Time 表的表结构是固定的，包含三个字段：

| 字段 | 逻辑类型 | 说明 |
| - | - | - |
| `id` | 字符类逻辑类型 | 业务主键，建表后仅可修改类型（可选 `STRING` / `HASH` / `ADDRESS` / `TOKENID` / `TXID` / `BLOCKID` / `CHAINID`） |
| `time_at` | `TIMESTAMP` | 时间桶，建表自动创建 |
| `value` | `FLOAT` | 状态值，建表自动创建 |

底层会派生两张影子表：**主表**（保存每个对象最新桶）与 **`_archive`**（保存历史桶，`id` + `time_at` 复合标识）。

## 时间分桶规则

Time 表以**时间桶**为粒度记录状态，而不是记录每一笔原始写入：

* **最小时间桶固定为 60 秒**。写入的 `time_at` 会**向后取整、秒数归零**对齐——`17:04:35` 对齐到 `17:05:00`；边界秒数恰好为 0（如 `17:04:00`）时已经对齐，不做处理。
* **同一对象在 60 秒内只保存 1 个点**。
* **时间越久远，粒度越粗**：距当前越远，数据被压缩到更大的时间桶（如 3 天内为 1 分钟、更久远为 1 小时 / 1 天），历史数据越来越稀疏。

读取时返回 `time_at ≤ 查询时间戳` 的**最近一个已记录桶**，越久远越稀疏，但始终能取到最近的有效状态。

## 内置去重能力

你**不需要**在业务侧先做去重，也不用担心重复写入导致数据膨胀：

* **同一对象同一时间桶内只保留一个值**：重复往同一个 `id + time_at` 写入时，后写覆盖前值或直接跳过，不会产生重复行。
* **写入 API 内置实时压缩**：写入时，如果相邻两个点的值变化率小于固定阈值（当前为 **0.1%**），这行会被自动剔除、不落库。
* 因此业务可以把所有数据照单全收地交给 Time 表，BlockDB 会自动帮你决定哪些点值得记录。

## 离线压缩：自动优化存储

除了写入时的实时去重，BlockDB 还会**自动对历史数据执行离线压缩**：

* 压缩规则与实时压缩一致，持续剔除冗余点。
* 时间粒度变粗时，保留时间区间内 `time_at` 最大的那个点的值。
* 高并发写入或乱序批量导入产生的局部冗余点，会被后台任务逐步清理。

所以随着时间推移，历史数据会自动被精简，存储大小得到持续控制，越久远越紧凑。**你无需自己设计"每隔多久存一个点"的降采样逻辑。**

## 读写接口

| 接口 | 说明 |
| - | - |
| `UpsertTimeRows(table_id, time_at, rows)` | 向某个时间桶批量写入。`time_at` 会自动向后对齐到整分钟桶；行内若含 `time_at` 字段会被忽略，以接口传入的 `time_at` 为准 |
| `GetValue(table_id, row_id, time_at)` | 读取某个对象在某个时间桶的状态，返回 `time_at ≤ 查询时间` 的最近已记录桶 |

## 示例：token 美元价格表

保存某 token 每分钟的美元价格：

```python theme={null}
from blockdb import TimeTable, Table

ID = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"   # 某 token

tt = TimeTable("token_time_demo")

# 写：按时间桶写入（17:04:35 会自动对齐到 17:05:00 桶）
tt.upsert_time_rows([{"id": ID, "value": 2543.12}], "2026-05-18 17:04:35")

# 读：最新桶的值（读主表）
latest = Table("token_time_demo").get_row(ID)

# 读：某个时刻的切面值（按桶对齐，取 time_at ≤ 锚点的最近桶）
row = tt.get_value(ID, "2026-05-18 17:04:40")
```

## 小结

* Time 表按**时间桶**管理序列数据，最小 60 秒，写入自动向后对齐。
* **内置去重**：同桶只留一个点，相邻值变化小于 0.1% 自动剔除，你无需担心重复写入。
* **离线压缩**：历史数据自动精简、存储持续优化，越久远越紧凑。
* 通过 `UpsertTimeRows` / `GetValue` 完成按时间读写。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.