· 国产自研 SQL 引擎 LIVE
企业级数据底座 · SQL 数据引擎 · 国产化开拓者

高性能企业级数据底座
国产自研 SQL 数据引擎

以自研数据库为内核的新一代国产数据基础设施 —— 高阶分析 SQL 全集、跨方言统一、海量数据永不 OOM, 单 jar 嵌入即查即得。

1000+
企业级客户 · 规模验证
0.57×
点查耗时 · 反超手写直读
4 方言
业界独有 · 存量 SQL 直跑
100%
自研可控 · 零境外依赖
01八大核心优势CORE ADVANTAGES

不是「能跑简单查询」的玩具, 而是把完整的分析型能力、跨方言兼容与内存鲁棒性集于一身。

海量数据永不 OOM

排序 / 聚合 / 去重 / JOIN / 窗口 / 集合运算全链路具备弹性内存自适应能力, 本地盘扛住单机内存放不下的数据, 大数据量稳如磐石。

极致单机性能

中等规模数据下亚秒级响应, 读取路径逼近甚至反超手写极致优化代码, 无集群调度开销, 启动即查询。

高阶分析语法齐全

窗口全集 + GROUPS 帧、GROUPING SETS/CUBE/ROLLUP、PIVOT、MATCH_RECOGNIZE、QUALIFY、分位与近似聚合全部到位;尤其 MATCH_RECOGNIZE 不只是能跑 Demo, 而是覆盖 Oracle 级高阶语义。

跨方言统一层

一个引擎同时听懂 MySQL / Oracle / PostgreSQL / SQL Server 的函数与语法, 业界独有;绝大多数存量 SQL 原样直跑, 迁移从「改写工程」降级为「回归验证」。

原生级 JSON 处理

14 个标准 JSON 函数 + ->/->> 箭头语法 + 按需精准提取, 大 JSON 列近乎恒定内存开销。

复杂子查询深度优化

多层嵌套复杂关联子查询智能优化, 内层数据只计算一次, 告别逐行慢扫;并能识别业界普遍退化的边界形态。

单机 ⇄ 分布式 · 灵活扩展

同一套自研内核:嵌入式单 jar 单机极致, 亦可服务化、按数据规模横向扩展为分布式计算节点;开放数据源接入, 自定义灵活扩展, 单机与分布式都是自研、自主可控的实现。

结果可信 · 零静默错误

不支持的边界一律给出明确报错与改写建议, 绝不悄悄返回似是而非的结果 —— 慢可以等, 数错了会误导决策;给管理层看的数, 敢签字。

02终极横向能力对比CAPABILITY MATRIX

与传统关系库、大数据 / 流批引擎、列存分析库全面对照。

领先 领先项 (嵌入式 / 单机同类中) ✓ 原生支持 ◐ 部分 / 受限 — 不支持
能力维度 YoungsData MySQL 8 PostgreSQL Oracle SQL Server Hive/Spark Flink Trino DuckDB
基础查询 (SELECT / JOIN / 分组)
窗口函数 (18 个)
多维聚合 ROLLUP / CUBE / GROUPING SETS
QUALIFY 窗口结果直接过滤 领先
MATCH_RECOGNIZE 行模式识别 (完整 NFA) 领先
PIVOT / UNPIVOT 行列转置 领先
GROUPS 窗口帧 (SQL:2011 高阶帧) 领先
WITHIN GROUP 分位 / 中位
近似聚合 HLL / 海量数据快速估算
复杂关联子查询智能优化
JSON 高效处理 (恒定内存) 领先
跨方言函数 / 语法兼容 独有
海量数据永不 OOM (弹性内存) 领先
嵌入式部署 (单 jar · 零集群) 领先
中等数据查询延迟 极低

注:Hive/Spark/Flink 为大数据 / 流批引擎, 与本引擎(嵌入式 OLAP)定位不同, 此处仅就 SQL 分析语法与查询特性维度对照。

03SQL 语法能力全景SQL SYNTAX PANORAMA

完整的分析型 SQL 语法收入囊中, 且几乎所有「不支持」都是带改写提示的明确报错, 而非静默错误。

语法类别 支持 覆盖明细
查询骨架 SELECT / WHERE / GROUP BY / HAVING / ORDER BY / DISTINCT,LIMIT·OFFSET·FETCH 高效分页,WITH RESUME / RESUME ? 断点续读(按令牌定位, 并发写下不重读已交付行, 令牌经 SELECT LAST_RESUME_TOKEN() 取回;独立服务形态),GROUP BY / ORDER BY 序号与别名,NULLS FIRST·LAST,Top-N 极速直取
条件判断 比较全运算符 / BETWEEN / IN / LIKE / ILIKE / SIMILAR TO / RLIKE·REGEXP / IS [NOT] DISTINCT FROM(NULL 安全)/ IS NULL
JOIN INNER / LEFT / RIGHT / FULL / CROSS / NATURAL, 多表 & 自关联, 派生表任意一侧(含外连接、聚合派生表)
集合运算 UNION / UNION ALL / INTERSECT / EXCEPT(排序归并)
子查询 标量子查询、IN / NOT IN / EXISTS / ANY / ALL / SOME、行构造 IN、多层复杂关联子查询智能优化
CTE 公共表达式 WITH 单个 / 多个、链式相互引用、多次引用的 CTE 智能复用(只算一次,N 处共享)
窗口函数 排名 / 偏移 / 分桶 / 取值 / 分布 / 聚合作窗口 / 分位窗口(18 个)+ ROWS·RANGE·GROUPS 三种帧 + 命名窗口 + QUALIFY
聚合函数 SUM/COUNT/AVG/MIN/MAX(DISTINCT)、STDDEV/VAR、统计 CORR/COVAR/REGR、分位 PERCENTILE/MEDIAN、布尔聚合、GROUP_CONCAT/LISTAGG/STRING_AGG、FILTER(WHERE)、近似 HLL / 海量数据快速估算
多维聚合 ROLLUP / CUBE / GROUPING SETS / GROUPING(_ID)
标量函数 (近 100 个) 字符串(~30)/ 正则 / 数学全集 / 日期时间 / 位运算 / 哈希 MD5·SHA·CRC·BASE64 / Oracle 格式化族 TO_CHAR·TO_DATE·TO_NUMBER / CAST·TRY_CAST / CASE·COALESCE·NVL·DECODE
JSON 14 个 JSON 函数(提取 / 判断 / 内省 / 构造)+ ->·->> 箭头语法 + 按需精准提取
FROM 高级形态 PIVOT / UNPIVOT、MATCH_RECOGNIZE(完整 NFA 回溯 + Oracle 高阶语义集)、TABLESAMPLE
DML INSERT…VALUES(单 / 多行 / 参数化 batch)、单表 UPDATE / DELETE, 标准条件路径完整;DELETE … LIMIT n 有界删除(命中集按物理扫描序取前 n 条);DELETE … RETURNING * 删除并返回被删行(可与 LIMIT 组合, 与普通 DELETE 同为语句级原子;独立服务形态)
DDL CREATE TABLE(列注释 / 主键 / 复合主键 / SHARD 分片 / SORT KEY 排序键 / 内联索引 / 行存声明 ROW FIXED·MIN)、ALTER TABLE(RENAME、ADD·DROP·RENAME COLUMN、ADD·DROP PRIMARY KEY、COMMENT、HISTORY RETAIN)、DROP TABLE、TRUNCATE、CREATE [UNIQUE] INDEX / DROP INDEX
元数据内省 DESCRIBE·DESC <表>、SHOW TABLES [LIKE]、SHOW COLUMNS FROM、SHOW INDEXES·INDEX·KEYS FROM、SHOW CREATE TABLE、SHOW SHARDS FROM(分片与物理文件占用)、SHOW HISTORY FOR(历史天表清单), 结果即结果集, 可直接被程序消费
账号与访问控制 CREATE·ALTER·DROP USER(SUPERUSER 属性建号时声明)、CREATE·DROP ROLE、GRANT·REVOKE(8 动词 × 全局/库/表三级作用域 + 仅全局的 ADMIN, WITH GRANT OPTION;表/库级拦截默认观察模式只审计不拦, 由服务端开关升为强制)、SHOW GRANTS;来源访问规则 CREATE·DROP ACCESS RULE / SHOW ACCESS RULES(「账号 × 网段」有序规则链, 按优先级首条命中、未命中放行, SQL 动态增删、即时生效、重启保留, 恒强制生效;独立服务形态)
04JSON 半结构化处理JSON PROCESSING

不是浅层字符串截取, 而是深入数据处理内核 —— 功能完整度与内存效率兼得。

领先 差异化领先 ✓ 支持 ◐ 部分 — 不支持
JSON 能力 YoungsData MySQL 8 PostgreSQL Oracle SQL Server
路径提取 EXTRACT / VALUE / QUERY
-> / ->> 箭头语法
存在 / 包含判定 EXISTS / CONTAINS
类型 / 长度 / 键 / 深度内省
构造 JSON_OBJECT / ARRAY
按需精准提取、恒定内存占用 领先
跨方言 JSON 函数名兼容 独有
价值内存占用与「你要取的字段」成正比, 而非与「JSON 文档大小」成正比 —— 大体积 JSON 列提取单字段近乎恒定内存开销, 尤其适合「关系列 + JSON 列混合分析」的现代数据场景。
05方言兼容SQL DIALECT UNIFICATION

一个引擎, 听懂四种「方言」 —— 天然的 SQL 迁移友好层,MySQL / Oracle / PG / SQL Server 的存量 SQL 大量可直接运行。

函数同义词归一

GROUP_CONCAT = LISTAGG = STRING_AGG、NVL = IFNULL、DATEADD = DATE_ADD …… 数十组自动归一。

Oracle 格式化族

TO_CHAR / TO_DATE / TO_TIMESTAMP / TO_NUMBER 完整格式 token,Oracle 存量逻辑平滑迁入。

大小写不敏感

标识符大小写无关, 贴合多数库习惯, 迁移免去大量改写。

列名智能纠错

列名拼错时给出最相近列名建议, 开发调试体验友好。

迁移价值一套报表系统动辄上千条存量 SQL, 换引擎逐条改写、逐条验证往往以人月计, 每一处改写都是一次出错机会。YoungsData 在引擎内核层原生归一四种方言 —— NVL 不必改成 IFNULL、TO_CHAR 不必改成 DATE_FORMAT, 绝大多数存量 SQL 原样直跑;少数方言语义差异明确报错并给出改写建议, 绝不静默吞掉 —— 迁移从「改写工程」降级为「回归验证」, 风险与工期一起降一个量级。
方言语义仲裁 · 同一写法, 按当前方言给出各库「母语」语义

铁律(2026-07-13 拍板): 各库互不冲突的语法/函数 —— MySQL 的 SUBSTRING_INDEX、PG 的 SPLIT_PART、Oracle 的 NVL —— 一律兼容并包、同时全支持, 与方言开关无关; 只有下面这些真语义冲突的极少数点, 才在求值处读 ctx.session.dialect() 分流。默认 MySQL 8(历史行为零迁移), 可用 -Dyoungsdata.sql.dialect=mysql|postgresql|oracleSessionContext.withDialect(...) 切换。

真语义冲突点MySQL 8 (默认)PostgreSQL 16Oracle 19c
除零 / 模零 1/0返 NULL抛除零错抛除零错
GREATEST/LEAST 含 NULLNULL 传染整体忽略 NULL 取非空极值NULL 传染整体
SUBSTRING 负起点从尾往回数数轴语义 (起点 clamp 到 1)从尾往回数
LEFT/RIGHT 负计数返空串反向裁剪 (去掉尾/头 n 个)返空串
TRIM 多字符裁剪集整串成组反复剥除码点集合逐字符裁多字符直接报错 (对齐 ORA-30001)
REGEXP_REPLACE 默认范围全部替换 · 反引用 $N只换首处 · 反引用 \N · 第 4 参是 flags全部替换 · 反引用 \N · 第 4 参是 pos
STDDEV/VARIANCE总体 (POP)样本 (SAMP)样本 (SAMP)
EXTRACT(EPOCH FROM ts)按会话时区取真瞬时秒naive 时戳 as-if-UTC按会话时区取真瞬时秒

└─ 表中是真冲突点; 除此以外的跨库函数与语法始终全部可用, 方言开关影响它们。

① 各库语法糖自动吸收

各数据库特有写法自动认得并归一, 且只作用于语法本身、不碰字符串字面量里的用户数据: 反引号标识符、a<=>b NULL 安全等值、::type 转换、VARCHAR2 / NUMBER(p,s) 类型、-> / ->> JSON 取值、紧凑 INTERVAL、0x 十六进制…… 存量 SQL 原样直跑。

② 工业级解析内核

成熟稳定的 SQL 解析内核, 标识符大小写不敏感、贴合各库习惯; 绝大多数语法解析与方言无关, 一套语句三库通吃。

③ 名字归一 · 一实现吃多库别名

240+ 标量别名 + 聚合别名映射到同一内置实现: LCASE/UCASE→LOWER/UPPER、STRPOS/LOCATE→INSTR、NVL/IFNULLGROUP_CONCAT=LISTAGG=STRING_AGGDATE_PART→EXTRACT…… 与 SQL / Fluent 走同一张名字表。

④ 仅冲突处按方言

只有上表那些真语义冲突点才按当前方言「跟随谁」, 且对性能几乎零影响; 其余语法一视同仁, 切换方言不重写、不折损速度。

Oracle 数字/日期格式引擎

TO_CHAR / TO_NUMBER / TO_DATE / TO_TIMESTAMP 完整 format-token 双向引擎, Oracle 存量格式化逻辑平滑迁入。

类型别名跨库归一

NUMBER/NUMERIC/DEC→DECIMAL、VARCHAR2/CLOB/TEXT/STRING→VARCHAR、INT8/BIGINT→BIGINT、BINARY_DOUBLE/FLOAT8→DOUBLE…… 与方言设置无关一律接住。

UPSERT 双风格

MySQL ON DUPLICATE KEY UPDATE(含 VALUES(col))与 PostgreSQL ON CONFLICT ... DO UPDATE/DO NOTHING(含 EXCLUDED.col)双方言同引擎。

-- 同一段跨库函数, 三方言下始终可用(互不冲突, 兼容并包)
SELECT NVL(name, '匿名'),                    -- Oracle 写法
       IFNULL(phone, '-'),                   -- MySQL 写法
       SPLIT_PART(email, '@', 2),            -- PostgreSQL 写法
       SUBSTRING_INDEX(path, '/', -1)        -- MySQL 写法
FROM   users;
-- 仅真冲突点跟随方言: 下句 1/0 在 MySQL 返 NULL, 在 PG/Oracle 报错
--   java -Dyoungsdata.sql.dialect=postgresql ...
SELECT amount / NULLIF(qty, 0) FROM orders;
06事务持久 · ACID 级写入引擎TRANSACTIONS & DURABILITY

不是「只读分析玩具」—— 内置完整的事务写入引擎: 跨表原子提交、断电不丢、崩溃后自动恢复到一致状态; 外加唯一/联合索引、双方言 UPSERT、变更订阅(CDC)与时间点恢复(PITR),分析与在线写入一体。

读已提交 + 读己写

事务内立即看得到自己未提交的写、外部看不到; 跨表跨语句一致, 天然规避更新过程中的自读乱序。

崩溃 all-or-nothing

断电 / 宕机重启后自动恢复: 每个事务要么整个生效、要么整个没发生, 绝不会留下「半个事务」; 未提交的自动回滚、对数据零残留。

commit() · 同步零丢失

调用返回即代表已安全落盘, 此后任意断电都不会丢本事务。最强持久档, 转账等零容忍场景首选。

commitAsync() · 异步 ≤10ms

返回极快、写入吞吐更高; 进程被杀零丢失, 真断电最多丢约 10ms(且以整事务为单位, 绝不半批)。默认持久档。

持久化对比 · 断电丢失窗口(异步吞吐档)
持久化档断电丢失窗口说明
YoungsData · commit() 同步0 · 断电零丢失返回即已落盘, 最强持久, 与各库最严档同级
YoungsData · commitAsync() 异步(默认)≤ 10ms吞吐优先; 进程被杀零丢失, 断电最多丢约一个组提交周期
MongoDB · 默认日志刷盘约 100msjournal 默认刷盘间隔约 100ms
MySQL · 放宽持久化(flush_log=2/0)约 1s约每秒刷一次盘

└─ 对比的是「吞吐优先 / 异步持久」这一档: YoungsData 异步窗口 ≤10ms, 比 MongoDB 约 100ms、MySQL 放宽档约 1s 紧一个数量级; 要绝对零丢失随时切 commit()(与各库最严档同级)。

唯一 / 联合 / 主键索引

CREATE [UNIQUE] INDEX 建唯一或普通索引、支持多列联合; 点查 / 等值 / 前缀 / 范围 / IN 自动命中。索引只加速、永不影响正确性。

UPSERT 双方言

MySQL ON DUPLICATE KEY UPDATE 与 PostgreSQL ON CONFLICT ... DO UPDATE / DO NOTHING 同引擎, 存量写入逻辑平滑迁入。

变更订阅 · 内建 CDC

可订阅已提交的行级变更做增量同步 / 物化视图 / 审计, 进程内、跨进程两种消费方式; 只交付已安全落盘的数据, 崩溃会回滚的绝不外流。

时间点恢复 PITR

周期快照 + 命令行还原到「近 N 天内任意时刻」, 整库或单表级, 原库零接触; 还原结果按事务批生效, 绝不含半个事务。

事务能力速览
维度YoungsData
隔离级别读已提交 + 读己写(事务内自见其写, 跨语句一致)
原子性跨表跨多行事务原子提交; 单条多行 DML 亦为一个原子批
持久化commit() 同步零丢失 / commitAsync() 异步 ≤10ms(默认)两档可选
崩溃恢复重启自动恢复到一致态; all-or-nothing, 绝无半事务
索引主键、唯一、普通、多列联合; 自动命中点查 / 范围 / IN
UPSERTMySQL ON DUPLICATE KEY · PostgreSQL ON CONFLICT 双方言
CDC / 变更订阅已提交行级变更可订阅, 进程内 + 跨进程消费, 至少一次投递
时间点恢复周期快照 + 还原到任意时刻(整库 / 表级, 原库零接触)
按天历史改删旧版本自动按天留存, 全链可正 / 倒序回放
大规模支持按主键分片写入; 超大事务自动落临时盘, 不撑爆内存
诚实边界SAVEPOINT / 跨会话快照隔离 / Serializable 暂不支持 —— 明确报错, 不静默兜底
写法 · 声明式 transact(首选)与命令式 begin
SqlEngine eng = SqlEngine.builder(dir).transactional().build();   // 开事务档
SqlQuery  sql = eng.sql();

// ① 声明式(首选): 正常返回自动 commit(同步落盘), 抛异常自动回滚, 冲突自动重试
sql.transact(txn -> {
    txn.executeUpdate("UPDATE account SET bal = bal - 100 WHERE id = ?", 1);
    txn.executeUpdate("UPDATE account SET bal = bal + 100 WHERE id = ?", 2);
});   // 跨两表原子; 高并发下总额精确守恒、无扣穿

// ② 命令式: try-with-resources, 忘 commit 自动回滚, 事务内 SELECT 读己写
try (SqlTxn txn = sql.begin()) {
    txn.executeInsert("INSERT INTO audit (id, note) VALUES (10, 'transfer')");
    Object[] mine = txn.one("SELECT note FROM audit WHERE id = 10");  // 立即可见
    txn.commit();        // 同步落盘: 返回即断电不丢
}
// 同步 vs 异步 —— 按业务对"丢失容忍度"选一档
txn.commit();        // 零丢失: 返回即已落盘, 转账/账务等零容忍场景
txn.commitAsync();   // 高吞吐: 返回快, 进程被杀零丢失, 断电最多丢约 10ms(埋点/流水)
-- UPSERT 双方言 + 唯一 / 普通索引
INSERT INTO up (id, n, v) VALUES (1, 77, 'd') ON CONFLICT (id) DO UPDATE SET n = EXCLUDED.n;  -- PG
INSERT INTO up (id, n, v) VALUES (1,  5, 'x') ON DUPLICATE KEY UPDATE n = VALUES(n);          -- MySQL
CREATE UNIQUE INDEX uq_email ON users (email);
CREATE INDEX        ix_city  ON users (city, level);   -- 多列联合
工程诚实每一条能力都有对应测试背书(高并发转账总额守恒、断电 all-or-nothing、时间点还原…)。同时诚实标注边界: SAVEPOINT、跨会话快照隔离与 Serializable 暂不支持 —— 遇到会明确报错, 而不是静默给出似是而非的结果。慢可以等, 数错了会误导决策。
07编程 API · 建引擎到写入一条龙PROGRAMMATIC API

一套「装配入口 SqlEngine + 双门面(SQL 文本 SqlQuery / Fluent no-SQL Db+D)+ 预编译 Prepared* + 三态消费(list / forEach / cursor)+ RPC 电报 spec」的完整编程式 API —— 每个入口都是一行一签名、可直接抄用。

SqlEngine 一站装配

builder(dir).build() 一次接好元数据 + 存储 + 查询门面; AutoCloseable 自动 flush 落盘。Builder 链式开关: 事务 / 索引 / 分表 / 历史 / 方言 / 只读 / 自带存储工厂。

SqlQuery · SQL 文本门面

查询三态 list / forEach / cursor + first / one / exists / count; DML executeInsert/Update/Delete; DDL executeDdl; 统一入口 execute(sql) 自动分派; detectKind(sql) 词法级 ~10ns 识别语句类型。

预编译 Prepared*

prepare / prepareInsert/Update/Delete: 一次解析优化, 后续只绑参执行。真 batch 比循环快 5-50×; DDL 改表后自动重编译, 无需手动 re-prepare。

Db + D · Fluent no-SQL

不写 SQL 字符串也能建表/增删改查: db.select(...).list(), 与 SQL 门面 1:1 语义、零解析开销、节点不可变线程安全。

Cursor 拉取式游标

while ((row = c.next()) != null) 惰性读一行、零缓冲最省内存; EOF 自动 close 不泄漏句柄。与 list/forEach 并列的第三种消费态。

SessionContext 会话

不可变可派生: 时区 / Locale / MathContext / castMode / batchSize / spill 预算 / 审计 / 方言…… withDialect / withCastMode / ... 链式派生, 环境敏感参数集中管控。

存储 SPI · 自定义数据源

ReaderFactory / WriterFactory / RowSink 开放接入: 行存、内存、Kafka、RPC 虚拟源皆可; 谓词下推经 ReaderContext.pushedOperators 传入, IndexInfo 驱动点查/范围决策。

RPC 电报 · spec 包

瘦客户端(仅 D + spec)组装 QuerySpecbyte[] 上线 → 服务端 Db.fromSpec 还原执行; 同电报再来零解码零重编译, 客户端看不到任何解析/执行类。

最快上手 · 建引擎 → 建表 → 插入 → 查询
try (SqlEngine engine = SqlEngine.builder(new File("/data/mydb")).build()) {
    SqlQuery sql = engine.sql();
    sql.executeDdl("CREATE TABLE orders (id BIGINT PRIMARY KEY, customer VARCHAR(64), amount DECIMAL(18,2))");
    sql.executeInsert("INSERT INTO orders (id, customer, amount) VALUES (1, 'Alice', 12.50)");
    Object[]       one  = sql.one ("SELECT customer FROM orders WHERE id = 1");
    List<Object[]> rows = sql.list("SELECT id, amount FROM orders WHERE amount > 1000");
}  // close() 自动 flush 落盘 + 关 reader/writer 池
预编译参数化 · 一次编译反复换参(真 batch 快 5-50×)
PreparedSqlQuery pq = sql.prepare("SELECT id FROM orders WHERE amount > ? AND status = ? LIMIT ?");
List<Object[]> r1 = pq.list(5000L, "PAID", 10L);
List<Object[]> r2 = pq.list(8000L, "PAID", 20L);          // 零 plan 开销

// 真 batch: 一批共享 1 次 borrow + flush, 大批量远快于循环 execute
PreparedInsertSqlQuery ins = sql.prepareInsert("INSERT INTO orders (id, customer, amount) VALUES (?, ?, ?)");
ins.executeBatch(List.of(new Object[]{1L,"A",10.0}, new Object[]{2L,"B",20.0}));

// 拉取式游标: 最省内存, EOF 自动 close
try (Cursor c = sql.cursor("SELECT id, amount FROM orders WHERE amount > 100")) {
    Object[] row;
    while ((row = c.next()) != null) process(row);
}
Fluent no-SQL · Db + D(import static … D.*, 像写 SQL 又不用拼字符串)
Db db = engine.db();
db.createTable("orders").column("id", Db.Type.BIGINT).pk()
  .column("customer", Db.Type.VARCHAR, 64).column("amount", Db.Type.DECIMAL, 18, 2).execute();

List<Object[]> r = db.select(col("o.id"), col("c.name"), sum(col("o.amount")).as("total"))
        .from("orders", "o")
        .join("customers", "c").on(eq(col("o.cust_id"), col("c.id")))   // JOIN 必须 .on/.using 收尾
        .where(gt("o.amount", 0L))
        .groupBy(col("o.id"), col("c.name"))
        .having(gt(col("total"), val(1000)))
        .orderBy(desc("total")).limit(20).list();

// RPC 电报: 客户端组装 → byte[] → 服务端还原执行
QuerySpec spec = QuerySpec.select(col("id"), col("amount")).from("orders").where(gt("amount", 1000L)).limit(10);
byte[] wire = SpecCodec.DEFAULT.encode(spec);            // 上线
List<Object[]> back = db.fromSpec(wire).list();          // 服务端 Db.fromSpec 直达车
直通取值 · row() 返回 RowRec(简单查询快 1.3–1.9×, GC 压力小一个数量级)
// 纯 SELECT(+ 可选 WHERE/LIMIT)可走直通路径: 跳过装箱拆箱, 每行不再新建 Object[]
if (sql.canRunRow(q)) {
    List<Order> os = sql.row().list(
        r -> new Order((Long) r.get(0), (String) r.get(1)),   // r 是 RowRec, get(i) 取值
        q);
}
// 预编译 + 直通 + 映射, OLTP 小查询最省; 直通视图同样有 list / forEach / first / one / batch
PreparedSqlQuery pq = sql.prepare("SELECT id, name FROM users WHERE city = ?");
List<Object[]> rows = pq.row().list("hangzhou");

└─ RowRec.get(i) 按表字段序取值; 需要按列名 / 类型化取值时用通用 Object[] 路径。计数 / 存在性用 count(sql) / exists(sql)。

写法自由同一个库, SqlQuery(SQL 文本)、Db+D(Fluent)、spec(RPC 电报)三种写法语义完全一致、可混用, 事务与 journal 行为不变。SQL 有编译缓存, Fluent 零解析, RPC 电报按字节 LRU 复用 —— 按团队习惯与调用场景自由选。
08安全特性 · 拒绝注入 / 脏数据 / 错答 / OOMSECURITY & ROBUSTNESS

以「参数化预编译从结构上根除 SQL 注入」为核心, 叠加写入值强校验、严格类型规则、扫描审计与内存预算守护, 形成一条 fail-loud 的纵深防线 —— 脏数据不入库、错答不返回、恶意查询打不爆内存。

参数化预编译 · 结构级免疫注入

? 参数在执行期只作为一个已类型化的值参与比较, 从不被拼回 SQL 文本、也从不重新解析 —— 再恶意的字符串实参也无法改变 SQL 结构。防注入靠数据与代码彻底分离, 而非转义黑名单。

占位符仅限「值位」

? 只能出现在 WHERE / SELECT / IN / HAVING / CASE 的值端; 字段名、表名、函数名、LIMIT/OFFSET 一律不接受参数 —— 从语法层杜绝「用参数拼出表名 / 关键字」这类变体。

写入值强校验 · 脏数据挡在库外

每行每列入库前强类型校验: VARCHAR 超长、DECIMAL 丢精度 / 超范围、整数越界一律报错而非静默截断 / 饱和; 非法类型的值直接拒收, 保证存储层约束不被绕过。

严格类型规则 · 拒绝静默错答

布尔 / 字符串禁入算术、CAST 溢出 / 未知目标类型一律报错, 废止「把 "abc" 悄悄当 0」这类静默兜底; 批量导入可切容错档(TRY_CAST 语义)让失败返 NULL。

扫描审计 + 可观测

可开启断言式审计: 同一物理表被重复扫描即报错(附违规表名); 也可挂被动观测钩子, 生产环境持续上报各表实际扫描次数。既护性能也护一致性。

内存预算守护 · 防 OOM / DoS

必须整体驻留的形态(子查询结果、右表缓冲、窗口分区、GROUP_CONCAT、分位数…)超预算即清晰报错而非静默 OOM; 能溢写到盘的算子内存优先、绝不打爆进程。

错误分级 · 可安全对外

SQL 层错误分「不支持」(可返 501)与「用户写错」(可返 400)两类, 供业务分流 HTTP 码; 错误消息受控、结构化, 不泄漏内部堆栈。

结果放大守护 + 最小攻击面

REPEAT / LPAD / RPAD 等结果超上限即报错(防「小输入撑出巨大结果」); 高风险复杂 DML(子查询删改、跨表写)默认关闭并给安全改写建议, 确需时才显式开启。

参数化预编译 vs 字符串拼接(正例 / 反例)
// ✅ 安全: ? 只当"值"比较, 永不改变 SQL 结构
PreparedSqlQuery pq = sql.prepare("SELECT id, amount FROM orders WHERE status = ? AND amount > ?");
List<Object[]> rows = pq.list(userInput, threshold);   // userInput 即使是  x' OR '1'='1  也只是一个字符串常量

// ✗ 危险: 把用户输入拼进 SQL 文本 —— 结构可被篡改(应改用上面的 ? 绑定)
// String sql = "SELECT ... WHERE status = '" + userInput + "'";

// 参数个数不匹配 / 未绑定 → 立即报错, 而非静默当 NULL 返回空集(比报错更危险)
pq.list(1);   // 抛异常: 参数数量不匹配(SQL 有 2 个 ?, 传入 1)
// 类型 / 审计 / 内存, 都是可选开的会话级开关(零开销)
SessionContext s = SessionContext.defaults()
        .withCastMode(CastMode.NULL_ON_ERROR)   // 批量导入: CAST 失败返 NULL 而非抛错
        .withAuditSingleScan(true)              // 断言: 同表被重复扫描即报错
        .withScanObserver(t -> metrics.mark(t)) // 监控: 上报每个物理表扫描次数
        .withSpillBudgetBytes(512L << 20);      // 内存预算: 超限清晰报错而非 OOM
账号体系与来源访问规则(独立服务形态)
-- 账号与授权: MySQL 8 风格 DCL, 8 个权限动词 × 全局 / 库 / 表三级作用域(ADMIN 仅全局); 本组语句均需管理员身份执行
CREATE USER etl IDENTIFIED BY 'Str0ng!Pass';
GRANT SELECT, INSERT ON sales.* TO etl;   -- 表 / 库级拦截默认观察模式(违规只记审计日志), 确认无误后由服务端开关升为强制
SHOW GRANTS FOR etl;

-- 来源访问规则: 「账号 × 网段」有序规则链(对齐 PostgreSQL pg_hba 模型), SQL 动态增删、即时生效、重启保留、恒强制
CREATE ACCESS RULE r_etl       ALLOW  etl FROM '10.20.3.0/24' PRIORITY 10;   -- etl 仅允许从专属网段登录
CREATE ACCESS RULE r_etl_close REJECT etl FROM ALL            PRIORITY 20;   -- etl 其余来源一律拒(其他账号不受影响)
CREATE ACCESS RULE r_default   REJECT ALL FROM ALL            PRIORITY 9999; -- 收口: 未命中任何规则默认放行, 「名单外全拒」须显式加这条
SHOW ACCESS RULES;             -- 输出可回放语句, 行序即求值序(按 PRIORITY 升序首条命中)
DROP ACCESS RULE r_etl_close;  -- 删除即刻生效, 只影响新连接; 本机 loopback 恒放行防误配自锁
安全哲学整条防线只做一件事: 要么正确, 要么清晰报错, 绝不静默给出似是而非的结果。注入靠数据 / 代码分离结构级免疫、脏数据靠写入校验挡在库外、错答靠严格类型规则堵死、OOM 靠内存预算守护兜底 —— 给管理层看的数, 敢签字。
09性能与海量数据处理PERFORMANCE & SCALE

不靠「分布式堆机器」, 而把单机的每一滴性能榨干、把内存鲁棒性做到极致。

1.0×
全列扫描
百万行 · 已贴齐理论下界
0.86×
条件过滤(反超)
百万行 · 只解析命中列
0.57×
主键点查(反超)
百万行 · 智能提前返回定位
永不 OOM
全链路弹性内存自适应

读取路径相对值(对照同机「手写极致优化直读」基准):比值越低越快,<1 即代表反超手写直读。

海量数据永不 OOM

全算子弹性内存自适应:内存不够先溢写本地盘续跑, 绝不 OOM、不拖垮宿主进程。

智能扫描复用

自关联、多次引用同表自动共享同一次扫描, 杜绝重复 I/O。

智能数据裁剪

过滤与列裁剪在源头一次完成, 只读必要的行与列, 从源头减负。

Top-N 极速直取

ORDER BY + LIMIT 用极速直取, 深翻页不爆内存。

预编译多级缓存

编译产物多级缓存, 高 QPS 在线查询 CPU 开销趋零。

毫秒级启动

嵌入式无集群、无调度, 进程内启动即查询, 中等数据亚秒响应。

弹性水平扩展

服务化为分布式计算节点, 按数据规模横向加机, 吞吐随节点近线性增长。

海量智能分治

海量数据自动分治, 精准定位只读命中片区, 分而治之、线性提速。

维度 YoungsData 传统单机 DB
MySQL / PG
列存向量化
DuckDB / ClickHouse
分布式
Spark / Hive
启动 / 查询延迟 极低 高(集群调度)
内存鲁棒性 永不 OOM 磁盘临时表硬扛 部分支持 弹性内存自适应
复杂分析 SQL 第一梯队
中等数据延迟 极优 差(stage 开销)
嵌入 / 集成成本 极低(单 jar)

注:即便以 out-of-core 著称的 DuckDB, 官方文档至今仍专设 OOM 排查指南(部分聚合 / PIVOT / 多阻塞算子组合场景);YoungsData 将全部物化算子纳入弹性内存自适应, 无豁免算子。

10海量报表 · 多源多结果集融合MULTI-SOURCE REPORTING

复杂报表、跨源融合、多结果集合并 —— 一条 SQL 搞定, 无需在应用层来回搬运数据。

多结果集合并

UNION / UNION ALL 单次扫描融合,INTERSECT / EXCEPT 排序归并 —— 多张报表结果一次性合并去重。

公共子结果复用

多次引用的 CTE 只计算一次、多处共享, 复杂报表的公共中间结果不重复跑。

多表 / 多源关联

多表 JOIN、自关联、派生表任意一侧, 关系数据与 JSON 列混合关联, 跨源数据一查到底。

行列转置报表

PIVOT / UNPIVOT 原生支持, 交叉报表、宽窄表互转一条 SQL 完成。

多维汇总

ROLLUP / CUBE / GROUPING SETS 一次出多层小计与总计, 经营报表的「合计行」自动生成。

窗口分析直出

窗口函数全集 + GROUPS 帧 + QUALIFY:同比环比、累计、移动平均、分组 Top-N, 一句直出。

海量去重 · 近似估算

精确去重 + HLL 近似去重计数, 亿级基数秒级估算, 大报表统计不卡。

海量不爆内存

合并 / 聚合 / 排序全链路可弹性内存自适应, 单机内存放不下的大报表也能稳稳跑完。

11自定义灵活扩展 · 单机 ⇄ 分布式双形态EMBEDDED ⇄ DISTRIBUTED

一套自研引擎内核, 既能单机极致、又有自研的分布式数据处理逻辑。业务只需描述「表是什么、数据在哪」, 引擎负责 SQL 全栈 —— 按数据规模自由伸缩, 小到嵌入边缘设备, 大到分布式计算集群节点。

开放数据源接入

不绑定任何特定存储:业务实现标准接入层即可对接任意存储 / 文件格式 / 分库分表, 引擎负责其上全部 SQL 解析、优化、执行 —— 灵活扩展的根基。

单机极致形态

嵌入式单 jar、零集群依赖、毫秒级启动;内存放不下也永不 OOM, 中等规模数据亚秒响应。

自研分布式数据处理

内建海量数据智能分治, 自动定位并只读取命中的数据片区 —— 海量数据分而治之的处理逻辑由引擎自研掌控。

横向扩展为计算节点

纯自包含、无外部依赖的执行内核, 可服务化(RPC)并作为分布式架构中的高性能计算单元横向扩展 —— 单点越强, 集群越强。

形态 状态 能力与场景
嵌入式 (JDBC · 单 jar) 现已支持 业务进程内分析、边缘计算、桌面分析, 零网络开销、最低延迟
独立服务 (RPC Server) 现已支持 多客户端共享、集中数据服务
分布式数据处理 (智能分治) 架构已支持 海量数据智能分治 + 源头精准读取, 单机内核作为分布式计算节点横向扩展
MPP 统一编排 持续演进 多计算节点统一调度, 突破单机数据规模上限
提示一套引擎, 两种身段:既是能嵌进业务进程的轻量单机分析内核, 又是具备海量数据智能分治处理逻辑、可横向扩展的分布式计算节点 —— 单机与分布式, 都是我们自研、自主可控的实现。
提示100% 自研 · 100% 纯 Java · 零 native 依赖:不携带任何 .so / .dll, 凡有 JVM 的平台(x86 / ARM / 国产化平台)即装即用;没有 JNI 边界的崩溃风险与失控的堆外内存, 不会把宿主 Java 进程拖下水。非境外开源内核的二次封装, 无许可证变更与断供风险 —— 国产化 / 信创选型, 可放心纳入。
12自定义函数 UDF · 把业务逻辑长进 SQLUSER-DEFINED FUNCTIONS

SQL 表达不了的业务逻辑(脱敏加密、用户轨迹、自定义统计……), 写个普通 Java 方法就能变成 SQL 函数、在查询里直接调。三种类型全覆盖, 每种都能一次返回多列 —— 简单到「一个注解 + 一个方法」。

传统数据库(MySQL / PostgreSQL 等)给不了这样的体验:存储过程语言受限, 能跑任意 Java 逻辑、引第三方库、还能热替换的方案在工程上几乎不存在, 自定义聚合更无从谈起。

YoungsData 用纯 Java 提供三种自定义函数 —— 单行(SCALAR)逐行变换、分组(GROUP)对整组数据 holistic 计算、流式(STREAMING)逐行累加, 三种都能一次产出多列结果;而对标 Spark / Flink, 我们在「怎么写、怎么配、怎么改」上简单一个量级 —— 尤其分组 / 流式聚合, 它们要继承 UDAF / AggregateFunction、实现一大堆方法和 schema, 我们只要一个方法。

而真正把这套 UDF 推上量级的, 是每种函数都能接一个 UdfState s —— 一个 put / get 的状态对象(就是下面例 ③ 里那个 stats,get 还能直接强转类型)。它不止在行与行、组与组之间保存中间量,更能在 SQL 执行时接住你从查询里传入的自定义参数 —— 漏斗的步骤定义、路径的规则、留存的时间窗、各种阈值……函数里一句 s.get(...) 取出来即用。于是同一个 UDF 不再写死, 而是按查询参数化:SQL 负责把海量数据筛出来,UdfState 负责带着「参数 + 状态」边扫边算。

执行期传参 · 杀手锏这才是把自定义函数推到「海量数据处理无敌」的关键:普通 UDF 往往把逻辑写死、只能算一种;而这里的 UDF 能在查询执行时被传参 —— 同一个函数, 换一组参数就换一种算法。「SQL 决定算哪些数据」叠加「查询参数决定怎么算」, 让单行 / 分组 / 流式三种 UDF 直接长成一个可编程的海量数据分析算子:几行 Java + 一句 SQL, 就能在十亿级数据上跑参数化的漏斗、路径、留存与自定义状态机, 边扫边算、不缓冲整组、不 OOM。业务团队不碰引擎内部, 就把整套算法连同它的参数一起「长」进了 SQL。

单行 SCALAR

逐行字段变换(加密、脱敏、格式化)。一个 Object f(UdfRow), 可一次返回多列(如密文 + 掩码)。对应 Spark UDF / Flink ScalarFunction。

分组 GROUP

对整组有序数据做 holistic 计算(用户轨迹、漏斗、留存)。引擎直接喂你整组行的迭代器, 一次遍历搞定, 返回多列。对应 Spark UDAF —— 它要继承 Aggregator, 实现 6 个成员(4 方法 + 2 Encoder)。

流式 STREAMING

逐行累加(自定义统计、状态机)。就一个任意名方法:逐行更新中间量、组末用 end 产出, 一次算出 min/max/avg 等多列。对应 Flink AggregateFunction —— 它要 3 个方法 + 自管 Accumulator 类。

jar 丢目录 · 热加载

打成 jar 放进目录即自动注册,SQL 立即可调;改完换个 jar 热更新、不停服。Spark / Flink 改函数要重新打包、重新提交集群作业。

三种类型 · 易用度对比

维度 YoungsData 传统库
MySQL / PG
Spark Flink
单行函数(标量) @Udf + 1 方法 继承 UDF1…22
或 functions.udf()
继承 ScalarFunction
重写 eval()
分组 / 聚合函数 1 方法 游标直给 继承 Aggregator
6 方法 + 2 Encoder 类型定义
继承 AggregateFunction
3 方法 + Accumulator POJO 类
流式累加函数 1 方法 逐行+end 同 Aggregator
无专用 API · 仍需同等 6 方法
同 AggregateFunction
自管 Accumulator · 组级内存
一函数返多列 returns 声明 构造 StructType + RowFactory
需手动 .getField() 拆列
返 Row + TypeInformation
需额外定义列类型 schema
注册方式 jar 丢目录自动 spark.udf.register()
代码注册 · 修改需重新提交作业
env.createTemporaryFunction()
代码注册 · 修改需重启 Job
热更新(不重启)
重新打包 + 提交集群作业

重启 Flink 作业才能加载

注:对比的是「自定义函数」的写法与二次开发体验, 非整体引擎定位。

一眼看懂:三种类型, 各省多少代码

① 单行 SCALAR · 手机号加密「一次返两列」(密文 + 掩码)vs Spark 返多列要 structreturns 直接声明
✕ Spark:UDF 返多列要拼 Row + StructType, 再注册
import org.apache.spark.sql.*;
import org.apache.spark.sql.types.*;

StructType out = new StructType()
        .add("cipher", DataTypes.StringType)
        .add("masked", DataTypes.StringType);

UDF1<String, Row> enc = phone -> {
    if (phone == null) return null; // null 也得自己判
    return RowFactory.create(
            aesEncrypt(phone),                          // 密文
            phone.substring(0, 3) + "****" + phone.substring(7)); // 掩码
};
spark.udf().register("encrypt", enc, out);
// 调用还得 .getField 拆列:
// SELECT encrypt(phone).cipher, encrypt(phone).masked …
✓ YoungsData
@Udf(name = "ENCRYPT",
        type = UdfKind.SCALAR,
        returns = { @Col(name = "cipher", type = UdfType.STRING),
                @Col(name = "masked", type = UdfType.STRING) })
public static Object encrypt(UdfRow row) {
    String phone = (String) row.value();
    if (phone == null) { return null; }

    return new Object[] {
            aesEncrypt(phone),                            // 密文
            phone.substring(0, 3) + "****" + phone.substring(7) // 138****5678
    };
}
SQL 怎么用:SELECT ENCRYPT(phone) FROM users —— 一次得到 cipher、masked 两列。
省在哪:多列输出只需在 returns 里声明、方法 return Object[] —— 不必拼 StructType、不必 RowFactory、不必手工注册;列名直接就是声明的名字。
② 分组 GROUP · 跟踪一个用户走过的路径(地点串 + 经停数)vs Spark UDAF 继承 + 6 方法 + 2 schema→ 1 个方法
✕ Spark:自定义聚合(UDAF)要继承 Aggregator, 实现一堆方法 + 缓冲 schema
case class Buf(path: String, n: Int)
case class Out(path: String, stops: Int)

object UserPath extends Aggregator[Row, Buf, Out] {
    def zero = Buf("", 0)
    def reduce(b: Buf, r: Row) = {              // 自己拼缓冲
        val p = r.getString(0)
        if (p == null) b                            // null 也得自己跳
        else {
            val sep = if (b.n > 0) " → " else ""
            Buf(b.path + sep + p, b.n + 1)
        }
    }
    def merge(a: Buf, b: Buf) =                  // 还要写 merge
        Buf(a.path + " → " + b.path, a.n + b.n)
    def finish(b: Buf) = Out(b.path, b.n)
    def bufferEncoder = Encoders.product[Buf]    // 还要两个 encoder
    def outputEncoder = Encoders.product[Out]
}
spark.udf.register("user_path", functions.udaf(UserPath))
✓ YoungsData
@Udf(name = "USER_PATH",
        type = UdfKind.GROUP,
        returns = { @Col(name = "stops", type = UdfType.INT),
                @Col(name = "path", type = UdfType.STRING) })
public static Object userPath(Iterator<UdfRow> rows) {
    int stops = 0;
    StringBuilder path = new StringBuilder();
    while (rows.hasNext()) {
        String place = (String) rows.next().value();
        if (place == null) { continue; }

        if (stops++ > 0) { path.append(" → "); }
        path.append(place);
    }
    return new Object[] {
            stops,            // 经停数
            path.toString()   // 路径
    };
}
// 结果: stops = 3, path = "公司 → 食堂 → 健身房"
SQL 怎么用:SELECT user_id, USER_PATH(place) WITHIN GROUP (ORDER BY create_time) FROM visits GROUP BY user_id
省在哪:Spark UDAF 要你手动维护缓冲、写 reduce / merge / 两个 encoder + 两个 case class;YoungsData 直接把整组有序行的迭代器交给你, 一次遍历就能算完、返回多列 —— 分组逻辑回归直觉。想算更复杂的(各时段去了哪、停留多久), 也只是在循环里多写几行, 甚至直接返回一段 JSON。大数据组内无序靠引擎内存优先+溢写, 不 OOM。
更进一步:方法签名加上 UdfState s, 把查询时传入的参数(路径规则、漏斗步骤、停留阈值)用 s.get 取出来 —— 同一个分组函数就成了可配置的路径 / 漏斗分析算子, 换组参数即换一种口径。
③ 流式 STREAMING · 一个方法同时算 min / max / avgvs Flink AggregateFunction Accumulator 类 + 4 方法→ 1 个方法
✕ Flink:自管 Accumulator 类 + 实现 4 个方法 + 定义结果类型
public static class Acc {
    double min = Double.MAX_VALUE, max = -Double.MAX_VALUE;
    double sum = 0;
    long cnt = 0;
}

public class StreamStats extends AggregateFunction<Row, Acc> {
    public Acc createAccumulator() { return new Acc(); }

    public void accumulate(Acc a, Double v) {
        if (v == null) return;             // null 也得自己判
        a.min = Math.min(a.min, v);
        a.max = Math.max(a.max, v);
        a.sum += v;
        a.cnt++;
    }

    public Row getValue(Acc a) {
        if (a.cnt == 0) return null;        // 空组也得自己处理
        return Row.of(a.min, a.max, a.sum / a.cnt);
    }

    public TypeInformation<Row> getResultType() {
        // 还得手定义 3 列类型
        return Types.ROW(Types.DOUBLE, Types.DOUBLE, Types.DOUBLE);
    }
}

tableEnv.createTemporarySystemFunction("stream_stats", StreamStats.class);
✓ YoungsData
@Udf(name = "STREAM_STATS",
        type = UdfKind.STREAMING,
        returns = { @Col(name = "min_v", type = UdfType.DOUBLE),
                @Col(name = "max_v", type = UdfType.DOUBLE),
                @Col(name = "avg_v", type = UdfType.DOUBLE) })
// s = 状态袋:put / get(get 可强转)。既存逐行中间量,也能接住 SQL 查询时传入的参数
public static Object stats(UdfState s, UdfRow row, boolean end) {
    if (end) {                       // 组末:产出一次
        long n = s.getLong("cnt", 0);
        if (n == 0) { return null; }     // 空组 → 各列 NULL

        return new Object[] {
                s.getDouble("min", 0),        // min
                s.getDouble("max", 0),        // max
                s.getDouble("sum", 0) / n      // avg
        };
    }

    Double v = (Double) row.value(); // 逐行:只累加
    if (v == null) { return null; }

    s.put("min", Math.min(s.getDouble("min", v), v));
    s.put("max", Math.max(s.getDouble("max", v), v));
    s.put("sum", s.getDouble("sum", 0) + v);
    s.put("cnt", s.getLong("cnt", 0) + 1);
    return null;
}
SQL 怎么用:SELECT symbol, STREAM_STATS(price) FROM ticks GROUP BY symbol
省在哪:没有 Accumulator 类、没有固定的 finish —— 就一个 @Udf 标注的任意名方法:end=false 逐行只累加中间量、end=true 组末产出一次(单列直接 return 值、多列 return Object[])。增量聚合 O(state) 内存, 海量数据逐行流过、不缓冲整组、不 OOM。
再加一层:把查询参数(阈值、时间窗、漏斗步骤……)在执行时传进来, 函数里 s.get 取出来,同一个 STREAMING 函数就能按查询算不同的统计 / 漏斗 / 状态机 —— 这正是「执行期传参」让 UDF 变无敌的地方。
一句话关系数据库根本给不了「用 Java 扩展 SQL 函数」, 自定义聚合更不可能;而比起 Spark / Flink,YoungsData 把单行 / 分组 / 流式三种自定义函数统一成同一个范式 ——「一个 @Udf 注解 + 一个任意名方法 + 一个 jar」, 还都能一次返多列。尤其聚合类, 它们动辄继承基类、写一堆方法 + schema, 我们只要一个方法。业务团队不必懂引擎内部, 就能把自己的算法长进 SQL。
13典型适用场景USE CASES

从嵌入式分析到 AI 生成 SQL 的执行底座,YoungsData 覆盖七大典型落地场景。

嵌入式分析 / 边缘计算

单 jar 嵌入,零集群,毫秒级启动。

复杂报表 / BI 后端

高阶分析语法齐全,一条 SQL 搞定复杂报表。

多源异构数据分析

关系 + JSON 混合查询,跨方言 SQL 直接跑。

在线低延迟查询服务

预编译缓存 + 点查早停,高 QPS 稳定低延迟。

中等规模大数据

内存放不下也不怕,弹性内存永不 OOM,本地盘扛住。

存量 SQL 迁移

听懂四种方言,存量报表 SQL 绝大多数原样直跑。

AI 生成 SQL 的执行底座

大模型生成 SQL 常混用方言 —— 四方言归一直接听懂;不支持即明确报错 + 改写建议,Agent 自纠错闭环;单 jar 毫秒启动,天然的进程内 SQL 沙箱。

更多场景持续扩展
14完整函数手册 · 速查FUNCTION MANUAL

内置 140+ 函数,11 大类全覆盖。输入关键词即时检索, 签名 + 说明一目了然 —— 开发者与 AI 即学即用。同义词(如 NVL / IFNULL)均可直接书写。

字符串32 数学35 日期时间30 位运算6 哈希/编码10 条件/NULL5 类型转换5 正则3 JSON14 聚合27 窗口18
① 字符串函数32
函数签名说明
UPPERUPPER(str)转大写
LOWERLOWER(str)转小写
TRIMTRIM([BOTH/LEADING/TRAILING][c FROM] str)去除首尾(或指定字符集)
LTRIMLTRIM(str)去除左侧空白
RTRIMRTRIM(str)去除右侧空白
CONCATCONCAT(a, b, …)拼接, 忽略 NULL
CONCAT_WSCONCAT_WS(sep, a, b, …)用分隔符连接, 跳过 NULL 值
SUBSTRING / SUBSTRSUBSTRING(str, start[, len])截取子串,1-based 按码点
LENGTH / CHAR_LENGTHLENGTH(str)字符长度(码点数)
OCTET_LENGTHOCTET_LENGTH(str)UTF-8 字节长度
BIT_LENGTHBIT_LENGTH(str)UTF-8 位长度
REPLACEREPLACE(str, from, to)子串全部替换
LEFTLEFT(str, n)取左 N 个字符
RIGHTRIGHT(str, n)取右 N 个字符
LPADLPAD(str, len, pad)左侧填充至指定长度
RPADRPAD(str, len, pad)右侧填充至指定长度
POSITION / LOCATEPOSITION(sub IN str)子串位置(1-based, 未找到 0)
INSTRINSTR(str, sub)子串首次位置(0=未找到)
INITCAPINITCAP(str)每个单词首字母大写
REVERSEREVERSE(str)反转字符串
REPEATREPEAT(str, n)重复 N 次(超 16M 字符报错防 OOM)
TRANSLATETRANSLATE(str, from, to)逐字符映射, 多余字符删除
SPLIT_PARTSPLIT_PART(str, delim, n)取第 n 段(1-based, 越界空串)
SUBSTRING_INDEXSUBSTRING_INDEX(str, delim, count)取前/后 count 段(负数取后)
FIND_IN_SETFIND_IN_SET(s, csv)s 在逗号集合中的 1-based 位置
STARTSWITHSTARTSWITH(s, p)前缀判定 → 布尔
ENDSWITHENDSWITH(s, p)后缀判定 → 布尔
CONTAINSCONTAINS(s, sub)子串包含判定 → 布尔
ASCIIASCII(str)首字符码点(空串 → NULL)
CHRCHR(n)码点转字符
LEVENSHTEINLEVENSHTEIN(a, b)编辑距离
OVERLAYOVERLAY(s PLACING r FROM start[ FOR len])子串覆盖替换
② 数学函数35
函数签名说明
ABSABS(x)绝对值
ROUNDROUND(x[, d])四舍五入到 d 位
CEIL / CEILINGCEIL(x)向上取整
FLOORFLOOR(x)向下取整
POWER / POWPOWER(base, exp)幂运算
SQRTSQRT(x)平方根
CBRTCBRT(x)立方根
EXPEXP(x)自然指数 e^x
LOG / LNLOG([base,] x) / LN(x)对数(单参=自然对数, 双参=指定底)
LOG10LOG10(x)常用对数(底 10)
LOG2LOG2(x)二进制对数(底 2)
MODMOD(a, b)取模(b=0 → NULL)
SIGNSIGN(x)符号 -1 / 0 / 1
GREATESTGREATEST(a, b, …)取最大(任一 NULL → NULL)
LEASTLEAST(a, b, …)取最小(任一 NULL → NULL)
SIN / COS / TANSIN(x) / COS(x) / TAN(x)三角函数(弧度)
ASIN / ACOS / ATANASIN(x) / ACOS(x) / ATAN(x)反三角函数 → 弧度
ATAN2ATAN2(y, x)双参反正切
PIPI()圆周率常量
RADIANSRADIANS(deg)角度转弧度
DEGREESDEGREES(rad)弧度转角度
TRUNCATETRUNCATE(x, d)向零截断到 d 位(不四舍五入)
TRUNCTRUNC(num[, d]) / TRUNC(date[, unit])数字截断 / 日期截断(按首参类型)
WIDTH_BUCKETWIDTH_BUCKET(x, lo, hi, n)等宽分桶 → 1..n
RAND / RANDOMRAND()[0,1) 随机 double
GCDGCD(a, b)最大公约数
FACTORIALFACTORIAL(n)阶乘(n>20 溢出报错)
③ 日期时间函数30
函数签名说明
YEARYEAR(dt)提取年
MONTHMONTH(dt)提取月
DAY / DAYOFMONTHDAY(dt)提取日
HOURHOUR(dt)提取小时
MINUTEMINUTE(dt)提取分钟
SECONDSECOND(dt)提取秒
QUARTERQUARTER(dt)季度 1-4
WEEK / WEEKOFYEARWEEK(dt)当年第几周
DAYOFWEEKDAYOFWEEK(dt)星期几(1=周日 … 7=周六)
DAYOFYEARDAYOFYEAR(dt)年内天序 1-366
LAST_DAYLAST_DAY(dt)当月最后一天
NOW / CURRENT_TIMESTAMPNOW()当前完整时间戳
CURRENT_DATECURRENT_DATE今日 00:00:00(纯日期)
EXTRACT / DATE_PARTEXTRACT(field FROM dt)提取字段(支持 EPOCH/QUARTER 等)
DATE_FORMATDATE_FORMAT(dt, pattern)按 pattern 格式化
DATE_ADD / DATEADDDATE_ADD(dt, INTERVAL n UNIT)日期加
DATE_SUB / DATESUBDATE_SUB(dt, INTERVAL n UNIT)日期减
DATEDIFF / DATE_DIFFDATEDIFF(dt1, dt2)天数差
DATE_TRUNCDATE_TRUNC('unit', ts)日期截断到单位
TIMESTAMPDIFFTIMESTAMPDIFF(unit, d1, d2)跨单位整数差(向零截断)
TIMESTAMPADDTIMESTAMPADD(unit, n, d)加 n 个 unit
ADD_MONTHSADD_MONTHS(d, n)加 n 个日历月(月末对齐)
MONTHS_BETWEENMONTHS_BETWEEN(d1, d2)月数差(小数)
CONVERT_TZCONVERT_TZ(ts, from_tz, to_tz)时区转换
UNIX_TIMESTAMPUNIX_TIMESTAMP([ts])epoch 秒(无参=当前)
FROM_UNIXTIMEFROM_UNIXTIME(sec)epoch 秒 → 时间戳
TO_CHARTO_CHAR(dt[, fmt])Oracle/PG 日期格式化
TO_DATE / STR_TO_DATETO_DATE(text[, fmt])解析为日期
TO_TIMESTAMPTO_TIMESTAMP(text[, fmt])解析为时间戳(保留小数秒)
④ 位运算函数6
函数签名说明
BITANDBITAND(a, b)按位与
BITORBITOR(a, b)按位或
BITXORBITXOR(a, b)按位异或
BITNOTBITNOT(a)按位取反
SHIFTLEFT / LSHIFTSHIFTLEFT(a, n)左移
SHIFTRIGHT / RSHIFTSHIFTRIGHT(a, n)算术右移
⑤ 哈希 / 编码函数10
函数签名说明
MD5MD5(str)MD5 摘要(32 位十六进制)
SHA1 / SHASHA1(str)SHA-1 摘要(40 位)
SHA256 / SHA2SHA256(str)SHA-256 摘要(64 位)
SHA512SHA512(str)SHA-512 摘要(128 位)
CRC32CRC32(str)无符号 32 位 CRC
TO_BASE64TO_BASE64(str)Base64 编码
FROM_BASE64FROM_BASE64(str)Base64 解码
HEXHEX(n)整数转十六进制串
BINBIN(n)整数转二进制串
UUIDUUID()随机 UUID(36 位)
⑥ 条件 / NULL 函数5
函数签名说明
COALESCECOALESCE(a, b, …)返回首个非 NULL
IFNULL / NVLIFNULL(a, default)空值替换
NVL2NVL2(a, b, c)a 非 NULL 返 b, 否则返 c
NULLIFNULLIF(a, b)a=b 返 NULL, 否则返 a
IF / IIFIF(cond, then, else)简单三元条件
⑦ 类型转换函数5
函数签名说明
CASTCAST(expr AS type)类型转换(INT/BIGINT/DOUBLE/DECIMAL/VARCHAR/DATE/TIME/TIMESTAMP …)
TRY_CAST / SAFE_CASTTRY_CAST(expr AS type)安全转换, 失败返 NULL
TO_NUMBERTO_NUMBER(text[, fmt])按格式解析为 DECIMAL
TO_CHARTO_CHAR(num, fmt)数字格式化(与 TO_NUMBER 对称)
FORMATFORMAT(num, d)数字千分位定标度 / 日期格式化
⑧ 正则函数3
函数签名说明
REGEXP_REPLACEREGEXP_REPLACE(str, pattern, repl)正则替换(全部匹配段)
REGEXP_EXTRACT / REGEXP_SUBSTRREGEXP_EXTRACT(str, pattern[, group])提取首次匹配的第 group 组(默认整体)
REGEXP_COUNTREGEXP_COUNT(str, pattern)不重叠匹配个数
⑨ JSON 函数14
函数签名说明
JSON_EXTRACTJSON_EXTRACT(json, '$.a.b')按路径提取文本(亦为 -> 目标)
JSON_VALUEJSON_VALUE(json, '$.a')提取标量并去引号(亦为 ->> 目标)
JSON_QUERYJSON_QUERY(json, '$.a')仅返对象 / 数组
JSON_UNQUOTEJSON_UNQUOTE('"abc"')去最外层 JSON 引号
JSON_EXISTSJSON_EXISTS(json, '$.a')路径存在判定 → 布尔
JSON_CONTAINSJSON_CONTAINS(json, cand[, '$.path'])包含判定(结构递归比对)
JSON_VALIDJSON_VALID(json)合法 JSON 判定 → 布尔
JSON_TYPEJSON_TYPE(json[, '$.path'])类型内省(OBJECT/ARRAY/STRING…)
JSON_LENGTHJSON_LENGTH(json[, '$.path'])对象键数 / 数组元素数
JSON_KEYSJSON_KEYS(json[, '$.path'])对象键集
JSON_DEPTHJSON_DEPTH(json)嵌套深度
JSON_OBJECTJSON_OBJECT(k1, v1, …)构造 JSON 对象
JSON_ARRAYJSON_ARRAY(v1, v2, …)构造 JSON 数组
JSON_QUOTEJSON_QUOTE(str)字符串转 JSON 字面量
-> (箭头)json -> '$.path'取 JSON 片段(等价 JSON_EXTRACT)
->> (箭头)json ->> '$.path'取标量文本(等价 JSON_VALUE)
⑩ 聚合函数27
函数签名说明
SUMSUM([DISTINCT] x)求和
COUNTCOUNT(*) / COUNT([DISTINCT] x)计数
AVGAVG([DISTINCT] x)平均值
MINMIN(x)最小值
MAXMAX(x)最大值
COUNT_IF / COUNTIFCOUNT_IF(cond)条件为真的行数
ANY_VALUEANY_VALUE(x)组内任一值
STDDEV / STDDEV_SAMPSTDDEV(x)样本标准差
VARIANCE / VAR_SAMPVARIANCE(x)样本方差
STDDEV_POPSTDDEV_POP(x)总体标准差
VAR_POPVAR_POP(x)总体方差
BOOL_AND / EVERYBOOL_AND(x)全真聚合
BOOL_ORBOOL_OR(x)任真聚合
GROUP_CONCAT / LISTAGG / STRING_AGGGROUP_CONCAT(x[, sep])字符串拼接聚合
PERCENTILE_CONT / MEDIANPERCENTILE_CONT(f) WITHIN GROUP (ORDER BY x)连续插值分位数(MEDIAN=0.5)
PERCENTILE_DISCPERCENTILE_DISC(f) WITHIN GROUP (ORDER BY x)离散分位数
BIT_ANDBIT_AND(x)按位与聚合
BIT_ORBIT_OR(x)按位或聚合
BIT_XORBIT_XOR(x)按位异或聚合
MODEMODE(x)众数(并列取最小)
CORRCORR(y, x)Pearson 相关系数
COVAR_SAMP / COVAR_POPCOVAR_SAMP(y, x)样本 / 总体协方差
REGR_SLOPE / REGR_INTERCEPT / REGR_R2REGR_SLOPE(y, x)线性回归:斜率 / 截距 / 判定系数 R²
REGR_COUNT / REGR_AVGX / REGR_AVGYREGR_AVGX(y, x)回归点数 / 自变量均值 / 因变量均值
REGR_SXX / REGR_SYY / REGR_SXYREGR_SXY(y, x)回归平方和 / 叉积和
APPROX_COUNT_DISTINCTAPPROX_COUNT_DISTINCT(x)近似去重计数(亿级基数秒级估算)
APPROX_PERCENTILEAPPROX_PERCENTILE(x, p)近似分位数(海量数据快速估算)
⑪ 窗口函数18
函数签名(OVER 子句)说明
ROW_NUMBERROW_NUMBER() OVER (…)行号(无并列)
RANKRANK() OVER (…)排名(并列跳号)
DENSE_RANKDENSE_RANK() OVER (…)密集排名(并列不跳号)
LAGLAG(x[, offset[, default]]) OVER (…)前 N 行的值
LEADLEAD(x[, offset[, default]]) OVER (…)后 N 行的值
NTILENTILE(n) OVER (…)等频分桶
FIRST_VALUEFIRST_VALUE(x) OVER (…)窗口内第一行的值
LAST_VALUELAST_VALUE(x) OVER (…)窗口内最后一行的值
NTH_VALUENTH_VALUE(x, n) OVER (…)窗口内第 N 行的值
PERCENT_RANKPERCENT_RANK() OVER (…)百分比排名
CUME_DISTCUME_DIST() OVER (…)累积分布
SUM / AVG / COUNT OVERSUM(x) OVER (…)聚合用作窗口
MIN / MAX OVERMIN(x) OVER (…)聚合用作窗口
PERCENTILE_CONT OVERPERCENTILE_CONT(f) WITHIN GROUP (ORDER BY x) OVER (…)整分区连续分位
PERCENTILE_DISC OVERPERCENTILE_DISC(f) WITHIN GROUP (ORDER BY x) OVER (…)整分区离散分位

窗口帧支持 ROWS / RANGE / GROUPS 三种 + 命名窗口(WINDOW w AS …)+ IGNORE NULLS + QUALIFY 过滤窗口结果。

未找到匹配的函数, 换个关键词试试 ~
15实战对比YOUNGSDATA IN ACTION

同一个业务需求, 传统数据库 / 大数据引擎写起来又长又绕,YoungsData 一条简洁 SQL 搞定 —— 下面都是真实可运行的写法。

重点导读 · 最建议先看的 4 个硬核例子

如果用户只看这一页的一小部分, 最该点开的就是下面这四段。它们不是“少写几行 SQL”那么简单, 而是直接证明 YoungsData 已经把 Oracle 级行模式识别做成了真正可用的嵌入式能力。

重叠匹配 必看 分类输出 / 排除噪声 高级 EXCLUSION 行隐藏 稀缺 综合高阶语义 王牌
① JSON 取多字段 + 过滤 —— 传统库不友好逐字段 JSON_VALUE逐字段 JSON_VALUE → 箭头直读
✕ 传统库(SQL Server / Oracle):无箭头语法
SELECT
    JSON_VALUE(payload, '$.user.name') AS user_name,
    JSON_VALUE(payload, '$.user.vip')  AS vip,
    CAST(JSON_VALUE(payload, '$.order.amount') AS DECIMAL(18, 2)) AS amount
FROM events
WHERE JSON_VALUE(payload, '$.status')   = 'paid'
  AND JSON_VALUE(payload, '$.user.vip') = 'true';
✓ YoungsData:-> / ->> 箭头直读
SELECT
    payload ->> '$.user.name' AS user_name,   -- 按路径直读,免 JSON_VALUE/CAST
    payload ->> '$.user.vip' AS vip,
    payload ->> '$.order.amount' AS amount
FROM events
WHERE
    payload ->> '$.status' = 'paid'
    AND payload ->> '$.user.vip' = 'true';
简化:箭头语法按路径直读, 告别满屏 JSON_VALUE() 与显式 CAST;超大 JSON 列恒定内存提取;同一套写法在 MySQL / Oracle / PG / SQL Server 间无需改写。
② 每个部门工资前 3 名复杂查询简化8 行子查询 → 3 行
✕ 传统库(MySQL / PG / Oracle):必须套子查询
SELECT dept, name, salary
FROM (
    SELECT dept, name, salary,
        ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) AS rn
    FROM emp
) t
WHERE rn <= 3;
✓ YoungsData:QUALIFY 直接过滤窗口结果
SELECT
    dept, name, salary
FROM
    emp
QUALIFY
    ROW_NUMBER() OVER (PARTITION BY dept
                       ORDER BY salary DESC) <= 3;
简化:QUALIFY 一句过滤窗口结果, 省去整层嵌套子查询 —— MySQL / PG / Oracle / SQL Server 都没有 QUALIFY, 只能套子查询。
③ 销售额按季度透视成宽表复杂查询简化4 段 CASE WHEN → 1 句 PIVOT
✕ 传统库(MySQL / PostgreSQL):手写 CASE WHEN
SELECT product,
    SUM(CASE WHEN quarter='Q1' THEN amount END) AS Q1,
    SUM(CASE WHEN quarter='Q2' THEN amount END) AS Q2,
    SUM(CASE WHEN quarter='Q3' THEN amount END) AS Q3,
    SUM(CASE WHEN quarter='Q4' THEN amount END) AS Q4
FROM sales GROUP BY product;
✓ YoungsData:PIVOT 原生
SELECT *
FROM sales
PIVOT (
    SUM(amount) FOR quarter IN ('Q1','Q2','Q3','Q4')   -- 新增季度只改这一行
);
简化:新增一个季度只改 IN 列表, 不必再加一串 CASE WHEN;MySQL / PG 无 PIVOT, 只能手写条件聚合。
④ 大数据分组取每组 TopNvs SparkDataFrame 算子链 + 集群 → 1 条 SQL
✕ Spark:DataFrame 算子链, 要起集群、打包提交
import org.apache.spark.sql.expressions.Window
import org.apache.spark.sql.functions._

val w = Window.partitionBy("dept")
    .orderBy(col("salary").desc)
df.withColumn("rn", row_number().over(w))
    .filter(col("rn") <= 3)
    .select("dept", "name", "salary")
    .show()
✓ YoungsData:一条 SQL, 单 jar 嵌入即跑
SELECT dept, name, salary
FROM emp
QUALIFY ROW_NUMBER() OVER (PARTITION BY dept
                           ORDER BY salary DESC) <= 3;
简化:无需编写 DataFrame 算子链、无需起 Spark 集群与作业调度 —— 嵌入式单 jar, 标准 SQL 即查即得。
⑤ 按天分组统计营收(最常用报表)vs Spark / Flink多算子拼装 → 1 条 SQL
✕ Spark / Flink:提时间 → 分组 → 聚合 多算子拼装
// Spark
df.withColumn("day", date_trunc("day", col("ts")))
    .groupBy("day", "product")
    .agg(sum("amount").alias("revenue"))
    .orderBy("day")
    .show()
// Flink DataStream 还需 WindowAssigner /
// Watermark / KeyedProcessFunction…
✓ YoungsData:一条 SQL, 恒定内存高效聚合
SELECT
    DATE_TRUNC('day', ts) AS stat_day,   -- 'hour'/'month' 粒度同理
    product,
    SUM(amount) AS revenue
FROM metrics
GROUP BY
    DATE_TRUNC('day', ts),
    product
ORDER BY stat_day;
简化:「时间分桶 + 分组聚合 + 排序」一条标准 SQL 完成, 无需编写 DataStream / DataFrame 算子, 也没有集群调度开销;亿行报表内存可控 —— 超限自动溢写, 不 OOM。
⑥ 漏斗转化:浏览 → 加购 → 支付(增长分析高频)传统库只能层层自关联3 层 JOIN 扫 3 遍表 → 1 段 PATTERN
SQL 怎么用:一段 PATTERN 描述用户行为序列, 引擎按事件顺序精准匹配 —— 留存、流失路径同理
✕ 传统库(MySQL / PG / SQL Server):逐步自关联拼漏斗
-- 每步先取「最早发生时间」,再层层 JOIN 校验先后
SELECT v.user_id, v.ts AS view_t, c.ts AS cart_t, p.ts AS pay_t
FROM (SELECT user_id, MIN(ts) AS ts
      FROM events WHERE event = 'view' GROUP BY user_id) v
JOIN (SELECT user_id, MIN(ts) AS ts
      FROM events WHERE event = 'cart' GROUP BY user_id) c
    ON c.user_id = v.user_id AND c.ts > v.ts
JOIN (SELECT user_id, MIN(ts) AS ts
      FROM events WHERE event = 'pay' GROUP BY user_id) p
    ON p.user_id = c.user_id AND p.ts > c.ts;
-- 三层自关联扫三遍表;每加一步漏斗,多一层 JOIN;
-- 且 MIN(ts) 藏语义陷阱:最早加购早于最早浏览时,
-- 真实走完路径的用户会被漏掉
✓ YoungsData:MATCH_RECOGNIZE,PATTERN 一行就是漏斗本身
SELECT user_id, view_t, pay_t
FROM events
MATCH_RECOGNIZE (
    PARTITION BY user_id                   -- 每个用户独立匹配
    ORDER BY ts                            -- 事件按时间排成序列
    MEASURES FIRST(viewed.ts) AS view_t,   -- 取首次浏览时间
             LAST(paid.ts)    AS pay_t     -- 取支付时间
    PATTERN (viewed carted+ paid)          -- 漏斗:浏览 → 加购(≥1次) → 支付
    DEFINE viewed AS event = 'view',       -- 每步的判定条件
           carted AS event = 'cart',
           paid   AS event = 'pay'
);
省在哪:PATTERN (viewed carted+ paid) 一行就是业务漏斗本身, 事件先后顺序由引擎保证、单遍扫描完成;改漏斗 = 改一行 PATTERN(加一步、改成 carted{2,} 都是一处改动)。传统库每加一步多一层 JOIN、多扫一遍表, 还要自己保证顺序语义不出错。
⑦ 连续三笔消费递减的用户预警(行为序列识别)vs Flink CEP专起一套 Flink + CEP 算子 → 1 条 SQL
SQL 怎么用:漏斗 / 留存 / 风控序列规则,SQL 直接表达 —— 不必为一条规则专起一套流计算
✕ Flink CEP:为一条规则起一个作业,Pattern API + 集群
Pattern<Order, ?> p = Pattern
    .<Order>begin("down")
    .where(new IterativeCondition<Order>() {
        public boolean filter(Order o, Context<Order> ctx)
                throws Exception {
            for (Order prev : ctx.getEventsForPattern("down"))
                if (o.amount >= prev.amount) return false;
            return true; // 递减才算命中
        }
    })
    .times(3).consecutive();

CEP.pattern(stream.keyBy(o -> o.userId), p)
    .select(/* 匹配结果还要自己拆装 */ …);
// 打包 → 提交集群作业;改规则,再来一遍
✓ YoungsData:MATCH_RECOGNIZE 一条 SQL, 嵌入式即跑
SELECT
    user_id, first_day, last_day
FROM orders
MATCH_RECOGNIZE (
    PARTITION BY user_id                          -- 逐用户检测
    ORDER BY order_date                           -- 按下单时间排序
    MEASURES
        FIRST(decline.order_date) AS first_day,   -- 首笔下跌日
        LAST(decline.order_date)  AS last_day     -- 第三笔下跌日
    PATTERN (decline{3})                          -- 连续 3 笔递减
    DEFINE
        decline AS amount < PREV(amount)          -- 比上一笔金额小
);
独一份:完整 NFA 行模式识别, 此前只存在于 Oracle / Trino / Flink 这类重型服务端引擎 —— 嵌入式引擎里这是独一份,DuckDB 至今没有。漏斗、留存、风控序列规则, 从「专起一套流计算」变成「一条 SQL」。
重点⑧ Oracle 级 MATCH_RECOGNIZE 进阶一:重叠匹配进阶 · 非常重要传统库只能硬拆多轮 JOIN → 1 条 SQL 连续找出所有重叠序列
SQL 怎么用:同一串事件里, 命中一个模式后不直接跳过, 而是从下一行继续匹配, 把所有重叠命中都找出来
✕ 传统做法:自己维护游标、窗口边界和重叠区间, 逻辑又长又容易错
以 100, 90, 80, 70, 60 这组金额为例:

想找出所有“连续 3 笔递减”序列时,
不是只找到 (90,80,70),
还必须继续找到重叠的 (80,70,60)。

传统 SQL / 代码流通常要:
1. 先取第一段
2. 手工回退起点一行
3. 再跑下一段
4. 自己保证边界不重不漏

规则一复杂,实现立刻失控
✓ YoungsData:重叠匹配直接写在 SQL 语义里
SELECT
    user_id, start_amt, end_amt
FROM orders
MATCH_RECOGNIZE (
    PARTITION BY user_id
    ORDER BY order_date
    MEASURES
        FIRST(DOWN.amount) AS start_amt,   -- 第 1 笔递减金额
        LAST(DOWN.amount)  AS end_amt      -- 第 3 笔递减金额
    AFTER MATCH SKIP TO NEXT ROW           -- 命中后从下一行继续,允许重叠
    PATTERN (DOWN{3})                      -- 连续 3 笔递减
    DEFINE
        DOWN AS amount < PREV(amount)      -- 当前金额小于上一笔
);
厉害在哪:AFTER MATCH SKIP TO NEXT ROW 不是锦上添花, 而是很多序列识别场景能不能做对的关键。风控、轨迹、行为链路里, 大量规则都要求“命中后继续找重叠模式”, 这类语义不少系统根本没有。
重点⑨ Oracle 级 MATCH_RECOGNIZE 进阶二:分类输出 + 排除中间噪声不是只返回“命中没命中” → 连每一行扮演什么角色都能给出来
SQL 怎么用:命中模式后, 不仅知道匹配成功, 还知道每一行属于 A/B/C 哪个角色, 并且可以把中间噪声行从输出里排掉
✕ 常见做法:先命中模式, 再自己回表二次拼角色, 还要额外过滤中间无效行
真实业务里经常不是“找到了就完了”,
而是还要继续回答:

1. 哪些行是起点?
2. 哪些行是中间过渡?
3. 哪些行只是参与匹配但不应该出现在最终结果里?

很多系统只能告诉你“命中了一个模式”,
但无法把匹配角色和输出裁剪一起做好。
✓ YoungsData:CLASSIFIER + EXCLUSION 直接把角色和输出控制写进 SQL
SELECT order_date, amount, cls
FROM orders
MATCH_RECOGNIZE (
    PARTITION BY user_id
    ORDER BY order_date
    MEASURES CLASSIFIER() AS cls             -- 返回当前行在模式中的角色名
    ALL ROWS PER MATCH                       -- 逐行输出匹配结果
    PATTERN (A {- B+ -} C)                   -- B 参与匹配,但从最终输出排除
    DEFINE A AS amount > 100,                -- 起始高值
           B AS amount BETWEEN 50 AND 100,   -- 中间过渡段
           C AS amount < 50                  -- 终止低值
);
专业度就体现在这里:很多引擎能做“模式命中”, 但做不到 CLASSIFIER() 这种角色级输出, 更做不到 {- B+ -} 这种“参与匹配但不输出”的精细控制。这个一旦有了, 风控标注、路径审计、行为解释性都会上一个档次。
重点⑩ Oracle / Trino 级 EXCLUSION 实战:峰值回撤只报“顶”和“修复”两端稀缺不是只会命中模式 → 连“参与统计但不展示”的中间下跌段都能精确控制
SQL 怎么用:量化里常见的“峰值回撤修复”事件, 只输出见顶日和修复确认日, 中间每个下跌日都不展示, 但回撤幅度和水下天数仍然要从这些隐藏行里算出来
数据库MATCH_RECOGNIZEEXCLUSION {- -}
Oracle 12c+✓ 标准制定者级
Trino / Presto
Snowflake△ 不完整
Flink CEP / 模式能力△ 部分
PostgreSQL / MySQL / SQL Server
BigQuery / Spark / Databricks
DuckDB / ClickHouse
✕ 绝大多数数据库:连 MATCH_RECOGNIZE 都没有, 更别说“隐藏中间过程行但继续统计”
真实业务里要找每一轮“从峰值跌下去,
又涨回峰值”的回撤事件时,用户真正想看的
通常只有两个信号点:

1. 见顶日
2. 修复确认日

中间连续下跌的过程日通常不想报出来,
否则结果会非常脏。

难点在于:
传统库就算能用 window + 自连接硬拼出结果,
也很难做到“把中间行从输出里拿掉,
但回撤幅度 / 下跌天数仍然按这些中间行计算”。
✓ YoungsData:EXCLUSION 让“参与匹配但不输出”成为 SQL 原生语义
SELECT
    sym, episode, role, d, px, trough, down_days, drawdown
FROM quote
MATCH_RECOGNIZE (
    PARTITION BY sym
    ORDER BY d
    MEASURES
        MATCH_NUMBER() AS episode,           -- 第几轮回撤
        CLASSIFIER()   AS role,              -- 当前是 PEAK 还是 RECOVER
        MIN(FALL.px)    AS trough,           -- 谷底:对隐藏的下跌日统计
        COUNT(FALL.px)  AS down_days,        -- 水下天数:对隐藏行统计
        PEAK.px - MIN(FALL.px) AS drawdown   -- 最大回撤
    ALL ROWS PER MATCH
    PATTERN (PEAK {- FALL+ -} RECOVER)       -- 中间连跌段参与匹配但不输出
    DEFINE
        FALL AS px < PREV(px),               -- 连续下跌
        RECOVER AS px >= PEAK.px             -- 涨回峰值即修复
);

真实输出形态

sym第几轮角色谷底下跌天数最大回撤
AAPL1PEAK11000
AAPL1RECOVER410185.0215.0
AAPL2PEAK51200
AAPL2RECOVER8122105.0215.0
这块真正稀缺的点不在“语法花哨”, 而在输出控制能力:{- FALL+ -} 把 8 天行情里 4 个中间下跌日全部隐藏, 最终只留下信号端点;但 MIN(FALL.px) 和 COUNT(FALL.px) 仍然对这些隐藏行生效。也就是说, 这条 SQL 统计了“最终不展示的数据”。这正是交易信号、行为事件和路径检测最想要的干净输出形态。
重点⑪ Oracle 级 MATCH_RECOGNIZE 进阶三:综合高阶语义一次打满王牌MATCH_NUMBER + CLASSIFIER + SUBSET + DEFINE 聚合/函数 → 一条 SQL 同时完成
SQL 怎么用:CLASSIFIER / MATCH_NUMBER / SUBSET / 重叠匹配 / DEFINE 内聚合与 ABS 一条 SQL 同时表达, 这不是“能写漏斗”那么简单
✕ 其他引擎:要么根本没有, 要么只能在 Oracle / Flink / Trino 这类重型服务端体系里做
常见引擎的真实情况通常是:

1. 只支持最浅层的序列匹配,再深一点就没有
2. 没有 CLASSIFIER / MATCH_NUMBER / SUBSET
3. 不支持 AFTER MATCH SKIP TO NEXT ROW 重叠匹配
4. DEFINE 里做变量组聚合或普通函数,很容易直接缺失
5. Oracle 虽然强,但部署形态是重量级服务端,不是单 jar 嵌入式

也就是说:
“能写一个漏斗 Demo” 和
“把 Oracle 级高阶语义完整跑通”
中间隔着一整代实现难度
✓ YoungsData:不是做样子, 而是按 Oracle 对齐测试套逐项跑通
SELECT order_date, amount, match_no, cls, avg_x
FROM orders
MATCH_RECOGNIZE (
    PARTITION BY user_id
    ORDER BY order_date
    MEASURES
        MATCH_NUMBER() AS match_no,                -- 当前是第几个命中的模式
        CLASSIFIER()   AS cls,                     -- 当前行扮演的角色
        AVG(X.amount)  AS avg_x                    -- DOWN/NOISE 子集上的运行均值
    ALL ROWS PER MATCH
    AFTER MATCH SKIP TO NEXT ROW                   -- 允许重叠匹配
    PATTERN (DOWN+ NOISE* RECOVER)                 -- 下跌序列 + 噪声 + 恢复
    SUBSET X = (DOWN, NOISE)                       -- 定义聚合子集 X
    DEFINE
        DOWN AS amount < PREV(amount),             -- 继续下跌
        NOISE AS ABS(amount - PREV(amount)) < 5,   -- 小幅波动视为噪声
        RECOVER AS amount > AVG(X.amount)          -- 高于运行均值才算恢复
);
为什么这条非常重要:它背后不是单点语法支持, 而是一整套 Oracle 风格行模式识别能力已经打通。内部对齐测试套已覆盖 13 组核心语义: 量词、PREV/NEXT/FIRST/LAST、变量组聚合、CLASSIFIER()、MATCH_NUMBER()、ALL ROWS PER MATCH、AFTER MATCH SKIP TO NEXT ROW 重叠匹配、SUBSET、PERMUTE、EXCLUSION、以及 DEFINE 内普通函数。全球范围内, 能把这组 Oracle 级高阶语义做到嵌入式单 jar 且按套件逐项对齐验证的, 基本看不到第二家。
⑫ 存量 SQL 混着方言写 —— 换到其他任何引擎都是批量报错逐条改写以人月计逐条改写以人月计 → 原样直跑
SQL 怎么用:Oracle 的 TO_CHAR / NVL 和 MySQL 的 GROUP_CONCAT 混在一条 SQL 里, 直接执行
✕ 其他引擎:认自家方言, 换引擎 = 全量改写
-- 下面那条 SQL,拿到各引擎试跑:
MySQL      : ERROR 1305 — FUNCTION TO_CHAR
             does not exist
PostgreSQL : ERROR — function group_concat(text)
             does not exist
SQL Server : 'NVL' is not a recognized
             built-in function name
Spark      : AnalysisException — Undefined
             function: GROUP_CONCAT

→ 换引擎 = 上千条存量 SQL 逐条改写、逐条回归,
  每一处改写都是一次出错机会
✓ YoungsData:四方言内核级归一, 原样直跑
SELECT
    TO_CHAR(create_time,'YYYY-MM') AS stat_month,   -- Oracle 写法
    GROUP_CONCAT(DISTINCT region) AS regions,       -- MySQL 写法
    NVL(SUM(amount), 0) AS revenue                  -- Oracle 写法
FROM orders
GROUP BY TO_CHAR(create_time,'YYYY-MM');

-- 一条 SQL 混写两家方言,YoungsData 直接执行 ✓
为什么独有:数十组函数同义词(NVL=IFNULL、GROUP_CONCAT=LISTAGG=STRING_AGG、Oracle 格式化族 TO_CHAR/TO_DATE……)在引擎内核层直接归一 —— 不是离线转写工具, 没有翻译步骤、就没有翻译错误。业界没有第二个引擎同时听懂四种方言, 这也是 AI 生成 SQL 时代的天然容错层:大模型混写方言, 照样直接跑。
16语法速查 · SQL 与 API 接口全览SYNTAX & API REFERENCE

一页速查:支持哪些 SQL 语法、开放哪些编程接口。函数明细见 §14 函数手册

SQL 语法速查
类别支持
语句SELECT · INSERT(含 INSERT ... SELECT)· UPDATE · DELETE · CREATE / ALTER / DROP / TRUNCATE(DDL)· CREATE TABLE ... AS SELECT(按查询输出类型建表);UPDATE / DELETE 的 WHERE 可含子查询(高风险形态默认关, 显式开启);DELETE ... LIMIT n 有界删除;DELETE ... RETURNING * 删除并返回被删行(独立服务形态)
元数据内省DESCRIBE · DESC · SHOW TABLES[LIKE] · SHOW COLUMNS FROM · SHOW INDEXES / INDEX / KEYS FROM · SHOW CREATE TABLE · SHOW SHARDS FROM · SHOW HISTORY FOR;返回普通结果集, 可被程序直接消费
SELECT 子句WHERE · GROUP BY · HAVING · DISTINCT · ORDER BY(ASC/DESC · NULLS FIRST/LAST)· LIMIT · OFFSET · FETCH · QUALIFY · WITH RESUME / RESUME ?(断点续读, 独立服务形态)
JOININNER · LEFT · RIGHT · FULL · CROSS · NATURAL · 逗号隐式;ON / USING;自关联 · 派生表 / 子查询作一侧
集合运算UNION · UNION ALL · INTERSECT · EXCEPT
子查询标量 · IN / NOT IN · EXISTS · ANY / SOME · ALL · 行构造 (a,b) IN · 关联去关联 · 派生表 · LATERAL
CTEWITH(非递归链式)· WITH RECURSIVE(递归到不动点)
窗口 & 帧18 窗口函数;PARTITION BY / ORDER BY;帧 ROWS / RANGE / GROUPS + 五种边界;EXCLUDE 四态;IGNORE / RESPECT NULLS
多维聚合GROUP BY · ROLLUP · CUBE · GROUPING SETS · GROUPING()
比较运算= · <> · > · >= · < · <= · IN · LIKE / ILIKE · REGEXP / RLIKE · SIMILAR TO · BETWEEN · IS [NOT] NULL · IS [NOT] DISTINCT FROM · <=>;时间列可直接与字符串字面量 / 参数比较(WHERE d >= '2026-01-01', 与写 DATE '…' 结果一致;格式不认当场报错)
逻辑 / 算术AND · OR · NOT;+ - * / %;CONCAT · || ;JSON -> · ->> ;位运算函数
高级表算子派生表 · VALUES · TABLESAMPLE · PIVOT · UNPIVOT · MATCH_RECOGNIZE · LATERAL
表达式CASE WHEN(简单 / 搜索)· INTERVAL 运算 · CAST / TRY_CAST / SAFE_CAST · 参数 ? · AS 别名
数据类型INT · BIGINT · FLOAT · DOUBLE · DECIMAL · VARCHAR · CHAR · BOOLEAN · DATE · TIME · TIMESTAMP;时间为墙钟语义——存进去的年月日时分秒读出来一字不差, 与服务器时区 / 会话时区无关
函数标量约 182 · 聚合 38(含统计 / 回归 / 分位 / 近似)· 窗口 18 —— 明细见 §14 函数手册
方言MySQL(默认)· PostgreSQL · Oracle —— 无冲突并包, 仅冲突处按方言
API 接口速查
入口职责关键方法
SqlEngine装配入口builder(dir).build() · sql() · db() · close()
SqlEngine.Builder链式装配transactional · snapshots · pkIndexed · declarativeIndexes · sharded · historyByDay · dialect · readOnly · noDdl
SqlQuerySQL 文本门面list · forEach · cursor · first · one · exists · count · executeInsert/Update/Delete · executeDdl · execute · prepare* · begin · transact · row()
PreparedSqlQuery预编译 SELECTlist(args) · page · forEach · first · one · exists · count · cursor(args) · row()
Prepared{Insert/Update/Delete}预编译 DMLexecute(args) · executeBatch(List)
DbFluent no-SQL 门面select · insertInto · update · deleteFrom · createTable · createIndex · fromSpec
Db.Select查询构造器from · join / leftJoin / … · where · groupBy · having · distinct · orderBy · limit / offset · union / … · list / cursor / one / count
D表达式 / 条件工厂col · val · param · fn · cast · caseWhen · win · 聚合 sum / avg / … · 比较 eq / gt / in / … · 逻辑 and / or / not · 窗口 rowNumber / lag / …
SqlTxn事务句柄executeInsert/Update/Delete · list / one / … · commit · commitAsync · rollback · db()
Cursor拉取式游标next() · columnNames() · close()
SessionContext会话参数(不可变)defaults() · withDialect · withCastMode · withAuditSingleScan · withScanObserver · withSpillBudgetBytes · withZoneId
spec(QuerySpec / SpecCodec)RPC 电报(wire)QuerySpec.select(…) · SpecCodec.encode / decode · Db.fromSpec(byte[])

└─ 三种写法(SQL 文本 SqlQuery · Fluent Db+D · RPC 电报 spec)语义一致、可混用;详见 §07 编程式 API。

一句话总结

YoungsData 有 Oracle / Trino 级别的高阶分析语法, 有 DuckDB 级别的嵌入式轻量, 有 大数据引擎级别的永不 OOM 鲁棒性, 还有任何主流数据库都不具备的跨方言统一能力与高效 JSON 处理。

尤其在 Oracle 级 MATCH_RECOGNIZE 高阶语义这件事上, 我们不是"能演示", 而是已经把整套高级语义做成了真正可用的产品能力 —— 在国产 SQL 数据引擎这条赛道上, 这是极少数团队能做到的深度。