条件过滤和更新功能

条件过滤和更新包含条件过滤condition 入参)和更新操作operation 入参)两部分。本文从功能和能力的角度梳理 TcaplusDB 在这一特性上支持的范围、表行为差异、性能优化以及使用注意事项;类 SQL 文本的语法定义见《条件过滤和更新语法说明》。

1. 概述

conditionoperation 由两个独立的字符串参数承载,由 TcaplusDB 存储层统一解析和执行。一个写请求可同时携带前置过滤(condition)与后置更新(operation):

  • 仅当 condition 在记录的当前数据上成立时,更新或返回操作才会执行;否则请求返回 COMMON_ERR_CONDITION_NOT_MATCHED
  • 读类请求只携带 condition,用于过滤将要返回给客户端的数据。

文档分工:

  • 05条件过滤和更新语法说明》:类 SQL 的文本语法定义、操作符表、示例片段。
  • 本文(06):从能力维度回答 支持哪些命令、字段路径、运算符、内建函数、内建系统字段;TDR 与 PB 的差异;性能特征;常见限制与注意事项
  • 02PB表SDK_and_API/部分字段查询和更新》:与 PB 的 FieldGet/FieldSet/FieldUpdate 接口配合使用时的 字段路径集合 用法。

2. 功能概览

本节以"概览 + 差异 + 典型场景"的方式让你快速判断本特性是否能覆盖你的需求。详细形态见 §4 / §5。

2.1 主要能力清单

条件过滤(condition)

  • 比较:==!=<<=>>=,跨整型/浮点精度比较;字符串按字典序比较。
  • 逻辑:AND / OR / NOT,可加括号控制优先级。
  • 集合 / 范围:INNOT INBETWEEN ... AND ...
  • 字符串模糊匹配:LIKE / NOT LIKE,与 MySQL 一致,默认忽略大小写。
  • 数组包含:array CONTAINS (子条件) / NOT CONTAINS,子条件中用 $ 引用元素。
  • 位运算:&~<<>>,常用于 flag 判断。
  • 内建函数:size()length()substring()、类型转换(int/uint/float/double/string/bytes)。
  • 内建系统字段:$.LastAccessTime__version____ttl__、List 表的 __index__
  • 字段路径:支持嵌套字段、map 元素、数组元素及其嵌套字段。

更新操作(operation)

  • 数组的 PUSH / POP / SET / GET 命令式操作(TDR 表与 PB 表均支持)。
  • 标量字段自增/自减:pay.pay_times += 1level -= 1仅 PB 表的 operation 支持;TDR 表请使用专门的 Increase 请求命令实现字段自增)。
  • PB 表 map 元素的 PUSH / POP(按 key 插入或删除)。
  • 多个操作用分号 ; 串联,一次请求内顺序执行。

2.2 TDR 表 vs PB 表的关键差异

TDR 表 PB 表
Map 类型 不支持(TDR 协议无 map) 支持 map 元素的过滤、PUSH/POP,以及 schema-free 用法
数组的 refer 字段 自动维护:PUSH/POP 会自动改写 refer 不适用
SetValue 与复杂类型 SetValue() 写入的结构体/数组支持条件过滤和更新;请用 SetData() 不适用
数组元素的嵌套字段(pay_array[0].desc condition 中支持;更新只能通过 PUSH/SET/POP condition 中支持;字段集合更新(FieldSet)不支持,需借助 PUSH/SET/POP
operation 中的标量字段 += / -= 不支持;如需字段自增请使用专门的 Increase 请求命令 支持
自增命令 Increase 在 3.64.0+ 才支持 condition;低版本可改用 Update FieldInc/FieldIncrease 在 3.55.0+ 即支持
Schema-free 用法 受限 FieldSet + map 字段可实现,详见 Schema_Free

2.3 典型使用场景

场景 推荐写法
已存在则不重复加好友 condition = "friends NOT CONTAINS ($ = ?)" + operation = "PUSH friends #[-1] [$ = ?]"
限制等级上限的自增(PB 表) condition = "rank < 100" + operation = "rank += 1";TDR 表请改用 Increase 请求
维护固定大小数组(头插尾删) operation = "PUSH gameids #[0] [$ = ?]; POP gameids #[100]"
仅读最近未变化的记录 condition = "$.LastAccessTime < \"2024-01-01\""
删除过期邮件 operation = "POP mailbox #[0--1] [expire_time < ?]"
标志位过滤 condition = "flag & 8"

3. 支持条件过滤和更新的命令

下表汇总各类请求是否支持 condition/operation,以及对应 SDK 的最低版本要求。命令名以 PB SDK 为主,括号内是 TDR/底层等价名。

类别 命令 condition operation 备注
单记录读 Get - 3.55.0+
单记录读 FieldGet (PB) - 3.55.0+;与字段路径集合配合
单记录写 Insert - - 不参与条件流程
单记录写 Update 3.55.0+
单记录写 Replace 3.55.0+
单记录写 Delete - 3.55.0+
单记录写 FieldSet / FieldUpdate (PB) 3.55.0+;与字段路径集合配合
单记录写 FieldInc / FieldIncrease (PB) 3.55.0+
单记录写 Increase (TDR) 3.64.0+;低版本可改用 Update 实现自增
索引 / 部分键 IndexGet / GetByPartKey - 3.55.0+
索引 / 部分键 IndexDelete (PB) / DeletePartKey (TDR) - 3.64.0+
索引 / 部分键 UpdateByPartKey (TDR) 3.64.0+
全表遍历 Traverse / ListTraverse - 3.55.0+
数组 (TDR) UpdateItem (PUSH/SET/POP) 3.55.0+
数组 (TDR) Query (GET) 3.55.0+
List 表 ListGet / ListGetAll - 3.55.0+
List 表 ListReplace 3.55.0+
List 表 ListDelete - 3.55.0+
List 表 ListDeleteAll - 历史原因暂不支持
List 表 ListUpdateItem 3.55.0+
List 表 ListQuery 3.55.0+
Batch 读 BatchGet / BatchGetByPartKey / BatchFieldGet / ListGetBatch - 3.64.0+
Batch 写 BatchUpdate / BatchReplace / BatchDelete / ListDeleteBatch / ListUpdateBatch / ListReplaceBatch 3.64.0+

表中"3.64.0+"指 SDK 与 TcapSvr 版本同时达标。当前公开 SDK 最高为 3.55.0,因此 Batch 类的条件过滤/更新及 TDR 的 IncreaseUpdateByPartKeyDeletePartKey 的条件能力暂未对外开放,确有需求可联系 Tcaplus。

4. 条件过滤功能详解

4.1 支持的运算符与内建函数

condition 是类 SQL 的 WHERE 表达式,TcaplusDB 解析为统一的表达式树后执行。

  • 比较==/=!=/<><<=>>=。整型与浮点可跨精度比较,规则与 C++ 一致;字符串按字典序比较;数值与字符串之间不可比较。
  • 逻辑ANDORNOT,可使用括号控制优先级。
  • 位运算&(与)、~(取反)、<</>>(移位)。常用于 flag 字段判断,如 filter & 8
  • 范围BETWEEN ... AND ...
  • 集合IN (v1, v2, ...)NOT IN (...)
  • 模糊匹配LIKENOT LIKE,仅作用于字符串字段;与 MySQL 一致,默认忽略大小写,% 匹配任意字符串、_ 匹配单字符。
  • 数组包含array CONTAINS (子条件)array NOT CONTAINS (子条件),括号中的子条件可使用 $ 引用当前数组元素,详见 §4.4。
  • 内建函数(函数名不区分大小写):
    • 类型转换:int(x)uint(x)float(x)double(x)string(x)bytes(x)
    • 长度类:length(s)(字符串字节长度)、size(arr|map)(数组或 map 元素个数,可用于 size(mailbox) = 0 判断空数组/空 map)。
    • 字符串:substring(s, begin[, length])

4.2 字段路径

字段路径在 condition 中作为标识使用,TcaplusDB 解析后会按照表的元信息逐级解析。下面列出的路径形态在 TDR 表与 PB 表中均支持(差异之处会单独说明)。下面以一个 PB 表为例说明(表结构与《部分字段查询和更新》一致),TDR 表把对应字段换成 TDR 表定义即可:

message tb_online3 {
    int32  openid = 1;
    string timekey = 3;
    pay_info pay = 5;                      // 嵌套 message
    repeated pay_info pay_array = 6;       // 数组
    repeated string   desc_array = 7;
    map<int32, all_type_t>  int_map = 9;
    map<string, all_type_t> str_map = 10;
}

支持的路径形态:

  • 一级字段timekeyopenid
  • 嵌套字段(任意层级)pay.order.descpay.pay_times,例如 TDR 表中的 single_struct.sub_field
  • 数组元素pay_array[0]desc_array[3],下标 -1 表示尾部。TDR 表的标量数组同样支持,例如 items[-1]
  • 数组元素的嵌套字段pay_array[0].descpay_array[0].order.desc,TDR 结构体数组同样支持,例如 struct_array[0].titlesingle_struct.sub_array[0].x 这样路径中只含一个 [] 的形态。可使用 pay_array[0-100] 这样的范围(仅在 Query/GET 等数组取值场景使用,普通 condition不接受范围,请用单下标或 CONTAINS)。
  • Map 元素int_map[1001]str_map['key']str_str['key']仅 PB 表,TDR 协议无 map)。
  • Map 元素的嵌套字段str_map['key'].desc仅 PB 表)。

不支持或需注意的形态:

  • 路径中不能出现两次容器下标:如 map['key'].a.sub_map['sub_key']pay_array[0].sub_array[1]a.b[1].c[2] 均不支持;同理嵌套数组(数组的元素又是数组)也不支持。
  • 普通 condition 中的数组下标只接受单下标(如 items[0]),不接受 items[0-2] 这种范围;范围仅用于 Query/GET 等专门的数组取值场景。
  • TDR 表的数组元素本身不可再为数组(TDR 协议本身限制)。
  • 字段名若与 SQL 关键字(如 keylikeupdate)冲突,需要使用反引号转义:`key` > 100。关键字集合参考 MySQL 5.7 Keywords

4.3 内建系统字段

下面这些字段不属于表定义,但可以在 condition 中直接引用,TcaplusDB 会从记录的元信息(属性头部)中读取:

  • $.LastAccessTime(等价 __last_access_time__):记录最后访问时间,秒级精度,可与字符串形式时间比较,如 $.LastAccessTime < "2024-01-01"
  • __version__:记录版本号。
  • __ttl__:记录的 TTL(秒)。
  • __index__(List 表,等价 -index):当前 List 元素的 index 值。

这些字段的好处是仅依赖记录的属性头部信息,参与过滤时通常不需要解包记录的 value 字段,性能更优(详见 §6)。

4.4 数组的 CONTAINS / NOT CONTAINS 与 $ 引用

array CONTAINS (子条件) 检查数组中是否存在满足子条件的元素:

  • 标量数组:用 $ 引用当前元素本身。例如 gameids CONTAINS ($ = 101)gameids NOT CONTAINS ($ = 101)
  • 结构体数组:直接使用元素的字段名。例如 mailbox CONTAINS (title = "tcaplus" AND read = 0)
  • 子条件可以是任意复杂的 AND/OR/NOT/IN/... 组合。

4.5 LIKE / IN / BETWEEN 的常见用法

  • name LIKE 'abc%' 匹配 abc 开头;name LIKE '_bc' 匹配长度为 3 且后两字符为 bc。
  • name IN ('abc', 'ABC', '123')level NOT IN (1, 2, 3)
  • score BETWEEN 60 AND 100 等价于 score >= 60 AND score <= 100

5. 更新(Operation)功能详解

operationcondition 同为类 SQL 文本,在写类请求中描述对记录的修改动作;多个动作之间可通过分号 ; 串联,TcaplusDB 在一次请求内顺序执行。

5.1 标量字段的自增/自减

仅 PB 表的 operation 支持这种用法。TDR 表的 operation 文本只支持 §5.2 的数组 PUSH/POP/SET/GET 操作,提交 field += 1 这类表达式会被 TcaplusDB 拒绝;TDR 表如需字段自增,请使用专门的 Increase 请求命令(不通过 operation 文本,而是请求体上独立携带要自增的字段和步长)。

PB 表支持对标量字段或嵌套标量字段使用 +=-= 进行原子自增/自减:

"pay.pay_times += 1"
"pay_map['kkk'].pay_times += 10"
"pay_array[0].pay_times -= 10"

+=-= 会被识别为字段自增更新;其它 *=/=&=|=operation 场景下不会作用到字段上。

5.2 数组的 PUSH / POP / SET / GET

针对 repeated 字段(PB)和数组字段(TDR),支持四种命令式操作:

  • PUSH:向指定下标插入元素。下标 -1 表示尾部。
    • 标量数组:PUSH gameids #[-1] [$ = 101]
    • 结构体数组:PUSH mailbox #[-1] [title = 'tcaplus', content = '...']
  • SET:覆盖指定下标的元素,下标必须已存在。SET gameids #[1] [$ = 101]
  • POP:删除元素,可指定下标范围或附加条件;删除不存在的下标不报错。
    • POP mailbox #[0-10] [title != 'tcaplus']
    • POP gameids #[100]:删除第 100 个,超过数组大小时无影响。
  • GET:返回数组某段(仅返回,不修改),常用于 Query/ListQuery 等数组查询请求。GET gameids #[0-9]

赋值类型:标量数组用 $ = 值;结构体数组用字段名 [a = ..., b = ...]。不同精度整型/浮点之间会按 C++ 强转规则转换,可能截断。

5.3 多条操作的组合

多个操作之间用分号 ; 连接,TcaplusDB 在一次请求内顺序执行:

"pay.pay_times += 1; PUSH gameids #[-1] [$ = 101]"
"PUSH gameids #[0] [$ = 100]; POP gameids #[100]"   // 头插尾删,保持数组长度 ≤ 100

5.4 与 PB 的 FieldSet / FieldUpdate 协同

PB 的 FieldSet(C++)/FieldUpdate(Go)以"字段路径集合 + message 增量数据 + operation + condition"四个入参一次完成请求:

  • 字段路径集合用于声明本次更新涉及的字段,message 中只填入这些字段的目标值。
  • operation 可携带数组操作或自增动作,作为字段集合更新之外的额外操作。
  • 涉及的字段路径集合本身的能力(嵌套字段、map 元素的插入/删除等)属于 字段更新,详见《部分字段查询和更新》。

6. 性能特征与优化

condition 通常不会带来明显额外开销:存储后端的瓶颈在 IO,CPU 上多一次条件判断对吞吐基本无感知。例如 GetByPartKey 扫描 100 条数据,无 condition 与有 condition 仅在 返回数据量 上有差异。

TcaplusDB 会根据 condition 表达式的特征选择不同的执行路径:

  • 仅 key 字段或属性字段:当条件只用到主键、索引字段或 $.LastAccessTime__version____ttl__ 等属性字段时,无需读取记录的 value 数据,可显著减少磁盘 IO。
  • SortList 表 + 仅排序字段:当条件只使用了 sort 字段时,可通过 List 的索引直接判断元素,无需打开记录。
  • SortList 表 + 单一排序字段 + 简单二元比较:例如 field >= 1field == 1,TcaplusDB 走二分查找路径,时延更低。
  • 其它情况退化为 逐条解包记录后再判断

性能优化建议:

  • 优先把过滤条件落在 key、index 或 sort 字段上。
  • 利用 $.LastAccessTime / __version__ 做"最近未变更才更新"等惯用模式时,几乎零额外开销。
  • 复杂的嵌套字段或数组 CONTAINS 条件需要解包整条记录,对单 key 操作影响有限,但用于全表扫描或大规模 IndexGet 时需谨慎。

7. 注意事项与限制

  • 文本最大长度conditionoperation 字符串各自最大 1023 字节。
  • SetValue 限制(TDR):TDR SDK 通过 SetValue() 设置的复杂类型(结构体、数组)字段不参与条件过滤/数组更新,必须使用 SetData();背景及跨实例 TDR 元数据版本兼容详见《TDR 表数据读写与版本兼容性》。
  • 数组 refer 字段(TDR):PUSH/POP 自动维护 refer 字段,业务无需手动同步。
  • 路径重叠(PB FieldSet/FieldGet):字段路径集合中不要出现"父子重叠"的路径,如 {"pay", "pay.order.desc"},否则更新顺序与最终结果不可预期;详见《部分字段查询和更新》。
  • [] 路径:路径中只允许出现一次方括号,不支持 map['k1'].sub_map['k2']arr1[0].arr2[1]
  • 关键字冲突:字段名命中 SQL 关键字时使用反引号转义。
  • 删除不存在的元素不报错:POP 给定的下标范围超出数组大小时,超出部分静默忽略。
  • 大小写:内建函数名不区分大小写;LIKE 默认忽略大小写。
  • Batch 命令的版本要求:所有 Batch 类的 condition/operation 需要 SDK 与 TcapSvr 同时 ≥ 3.64.0;当前公开 SDK 上限 3.55.0 暂未开放。
  • ListDeleteAll 暂不支持 condition,请改用 ListGetAll + 业务侧筛选 + ListDelete

8. 相关文档

results matching ""

    No results matching ""