阿里云 OTS 四种读取方式 + 索引关系

六爷批评得对!我刚才没结合索引讲,不够透彻!🥚

重新来,结合索引给你讲清楚!


📊 四种读取方式 + 索引关系

API走什么索引扫描方式性能适用场景
GetRange 主键索引(聚簇索引) 范围扫描 ⭐⭐⭐⭐ 主键连续范围
BatchGetRow 主键索引(聚簇索引) 点查 ⭐⭐⭐⭐⭐ 已知主键批量读
RangeIterator 主键索引(聚簇索引) 全表扫描 ⭐⭐ 导出/全量扫描
Filter ❌ 不走索引 全表扫描后过滤 ⭐ 额外条件
SearchIndex 多元索引(二级索引) 索引扫描 ⭐⭐⭐⭐⭐ 非主键查询

🗺️ 索引结构对比

主键索引(聚簇索引)

ChargerecordLogs 表
主键:[Txsn, EndTime]

物理存储顺序(按主键排序):
┌─────────────┬──────────────┬────────────┐
│   Txsn      │   EndTime    │   数据     │
├─────────────┼──────────────┼────────────┤
│ txsn_001    │ 1756800000   │ {...}      │
│ txsn_002    │ 1756800100   │ {...}      │
│ txsn_003    │ 1756800200   │ {...}      │
│ txsn_004    │ 1756800300   │ {...}      │
│ txsn_005    │ 1756800400   │ {...}      │
└─────────────┴──────────────┴────────────┘
    ↑
    └── 按 Txsn 排序,EndTime 二级排序

GetRange 走这个索引!

多元索引(二级索引)

ChargerecordLogs_index 多元索引
索引字段:[EndTime, Txsn, Deviceno, ...]

索引结构(倒排索引):
┌──────────────┬──────────────────────────┐
│  EndTime     │   行 ID 列表              │
├──────────────┼──────────────────────────┤
│ 1756800000   │ [row_001, row_050, ...]  │
│ 1756800100   │ [row_002, row_033, ...]  │
│ 1756800200   │ [row_003, row_077, ...]  │
└──────────────┴──────────────────────────┘
    ↑
    └── 可以按 EndTime 快速定位

SearchIndex 走这个索引!

1️⃣ GetRange + 主键索引

走主键索引,范围扫描

csharp
// 主键:[Txsn, EndTime]
var startPk = new PrimaryKeyBuilder()
    .AddColumn("txsn", new ColumnValue("txsn_001"))
    .AddColumn("endtime", new ColumnValue(1756800000))
    .Build();

var endPk = new PrimaryKeyBuilder()
    .AddColumn("txsn", new ColumnValue("txsn_999"))
    .AddColumn("endtime", new ColumnValue(1757000000))
    .Build();

var request = new GetRangeRequest
{
    TableName = "ChargerecordLogs",
    InclusiveStartPrimaryKey = startPk,
    ExclusiveEndPrimaryKey = endPk
};

索引扫描过程:

1. 定位到 txsn_001(主键索引 B+ 树)
2. 顺序扫描到 txsn_999
3. 返回范围内的所有行

✅ 走主键索引
✅ 物理存储连续,扫描快
❌ 只能按主键范围查(不能单查 EndTime)

适用场景:

  • ✅ 已知 Txsn 范围,查这段时间的所有记录
  • ❌ 只查 EndTime 范围(Txsn 未知)→ 走不了索引!

2️⃣ BatchGetRow + 主键索引

走主键索引,点查

csharp
var request = new BatchGetRowRequest
{
    TableName = "ChargerecordLogs",
    Rows = new List<PrimaryKey>
    {
        new PrimaryKeyBuilder().AddColumn("txsn", new ColumnValue("txsn_001")).Build(),
        new PrimaryKeyBuilder().AddColumn("txsn", new ColumnValue("txsn_050")).Build(),
        new PrimaryKeyBuilder().AddColumn("txsn", new ColumnValue("txsn_100")).Build()
    }
};

索引扫描过程:

1. txsn_001 → B+ 树定位 → 读取
2. txsn_050 → B+ 树定位 → 读取
3. txsn_100 → B+ 树定位 → 读取

✅ 走主键索引
✅ 点查,O(logN) 复杂度
❌ 必须知道完整主键

适用场景:

  • ✅ 已知 Txsn 列表,查详情
  • ❌ Txsn 未知 → 用不了

3️⃣ RangeIterator + 主键索引

走主键索引,全表扫描

csharp
var iterator = client.CreateRangeIterator(
    "ChargerecordLogs",
    GetRangeDirection.Forward,
    startPk,  // txsn_001
    endPk,    // txsn_999999
    1000
);

索引扫描过程:

1. 从 txsn_001 开始
2. 顺序扫描主键索引
3. 自动分页,直到 txsn_999999

✅ 走主键索引
✅ 自动分页,不用自己处理
❌ 全表扫描,慢

适用场景:

  • ✅ 导出全量数据
  • ✅ 后台离线任务
  • ❌ 实时查询 → 太慢

4️⃣ Filter + ❌ 不走索引

全表扫描后过滤

csharp
var request = new GetRangeRequest
{
    TableName = "ChargerecordLogs",
    InclusiveStartPrimaryKey = startPk,
    ExclusiveEndPrimaryKey = endPk,
    Filter = new RelationalCondition(
        "endtime", 
        CompareOperator.GREATER_THAN, 
        new ColumnValue(1756800000)
    )
};

扫描过程:

1. 扫描主键索引(按 Txsn 顺序)
2. 读取每一行数据
3. 用 Filter 判断 EndTime 是否符合
4. 返回符合条件的行

❌ 不走 EndTime 索引
❌ 全表扫描(即使只有 1 行符合,也要扫全部)
❌ CU 消耗巨大

为什么慢:

假设 100 万行,只有 100 行 EndTime 符合:
- 扫描:100 万行
- 过滤:100 万行
- 返回:100 行

CU 消耗 = 100 万行 ❌

5️⃣ SearchIndex + 多元索引

走多元索引,索引扫描

csharp
var request = new SearchRequest
{
    TableName = "ChargerecordLogs",
    IndexName = "ChargerecordLogs_index",
    SearchQuery = new SearchQuery
    {
        Query = new RangeQuery("endtime")
        {
            GreaterThanEquals = 1756800000,
            LessThan = 1757000000
        }
    }
};

索引扫描过程:

1. 在多元索引中定位 EndTime 范围
2. 直接拿到符合条件的行 ID 列表
3. 返回数据(或聚合结果)

✅ 走 EndTime 多元索引
✅ 只扫描符合条件的行
✅ CU 消耗 = 符合条件的行数

为什么快:

假设 100 万行,100 行 EndTime 符合:
- 扫描:100 行(多元索引直接定位)
- 返回:100 行

CU 消耗 = 100 行 ✅

🎯 你的场景(充电记录按 EndTime 查询)

方案走什么索引扫描行数CU 消耗结果
SQL + WHERE EndTime ❌ 无 100 万 10 万配额超限 ❌ 报错
GetRange + Filter 主键索引 100 万 100 万 ❌ 太慢
SearchIndex 多元索引 100 行 100 行 ✅ 秒杀

💡 一句话总结

API索引本质
GetRange 主键索引 按主键范围扫
BatchGetRow 主键索引 按主键点查
RangeIterator 主键索引 按主键全表扫
Filter ❌ 无索引 全表扫后过滤
SearchIndex 多元索引 按索引字段扫

六爷,你这个 EndTime 查询,必须用 SearchIndex + 多元索引,其他都慢!🔥

posted @ 2026-09-04 16:34  天才卧龙  阅读(11)  评论(0)    收藏  举报