fix(kingbase): 分页查询执行前剥除 DBX 拼入的 LIMIT/ORDER BY - #5876
Conversation
带 ORDER BY 的分页 GROUP BY 查询,在 DBX 中耗时约 2 分钟,而同一条 SQL 在 DBeaver 中不到 1 秒返回。 根因:DBX 核心做服务端分页时,把 `LIMIT n [OFFSET m]` 拼进语句,通过 execute_query 发给 kingbase-go agent。在金仓(PostgreSQL 规划器)上, 显式 LIMIT 会让规划器选"为取 N 行优化"的嵌套循环计划;对带 OR 连接条件的 LEFT JOIN,这意味着左表每一行都要做一次 bitmap 扫描(6 万多次,约 119 秒), 用户的 ORDER BY 又在其上叠加阻塞排序。而同一查询的 COUNT(*) 总数包装 (不带 LIMIT、ORDER BY 被忽略)走哈希连接 + HashAggregate,约 700ms。 修复:在 kingbase-go agent 的 executeQuery 中,当收到带尾部 DBX 拼入 LIMIT 的分页语句时: 1. 剥除其 LIMIT/OFFSET 与顶层 ORDER BY; 2. 把裸语句包进派生表,ORDER BY + LIMIT/OFFSET 移到外层: `SELECT * FROM (<裸聚合>) dbx_p <ORDER BY> LIMIT n+1 OFFSET m` 内层子查询(无 ORDER BY)保持快速的哈希连接 + HashAggregate 计划, 外层由服务端对聚合结果排序并正确分页,结果有序且 OFFSET 翻页正确; 3. ORDER BY 重写失败时自动回退到无序直接执行。 实测:该查询 119 秒 -> 约 1 秒(2000 行/页),结果按 ORDER BY 排序, 翻页正确。 范围:仅 agent 侧改动,不涉及 DBX 核心。
d33a820 to
0818c9d
Compare
t8y2
left a comment
There was a problem hiding this comment.
当前实现会改变用户 SQL 语义,暂时不能合入:
-
Agent 无法区分尾部
LIMIT/OFFSET是 DBX 注入还是用户原生 SQL。比如用户执行... LIMIT 1,core 可能原样保留,但 Agent 会把它当作分页语句重写为pageSize + 1,导致返回行数和内容改变。安全修复需要在 core/agent 协议中传递分页 provenance,不能仅凭 SQL 字符串形状推断所有权。 -
orderByQualifierRe全局删除 qualifier 会破坏合法表达式。例如SELECT t.id AS x ... ORDER BY t.id被包装成派生表后,外层ORDER BY id并不存在;失败后又静默退化为无ORDER BY/LIMIT/OFFSET的 bare 查询,后续页可能重复第一页并丢失排序语义。 -
当前顶层
ORDER BYscanner 不理解字符串、quoted identifier、line/block comment 或 dollar quote,合法 SQL 中的ORDER BY文本和括号会被误识别。
请将分页所有权放到结构化协议/core 重写边界,并复用 SQL-aware tokenizer/rewriter;无法证明等价时应保留原 SQL,而不是执行无序 fallback。回归测试至少覆盖用户 LIMIT 1、用户 LIMIT/OFFSET、UI 首/后续页、qualified alias、表达式、quoted identifier、注释和字符串中的 ORDER BY。
本 review 绑定 exact head 0818c9d1。未新增外部依赖,git diff --check 已通过;该 exact head 当前只有 label check,尚无 code CI。
问题
带无索引
ORDER BY的分页GROUP BY查询,在 DBX 中耗时约 2 分钟,而同一条 SQL 在 DBeaver 中不到 1 秒返回。复现 SQL(金仓 KingbaseES,连接的
jr_wf库):