LLM集成数据库的幻觉治理:当AI给出的SQL建议是错的

目录

  • [1. 问题的起点:乐观接入,悲观翻车](#1. 问题的起点:乐观接入,悲观翻车)
  • [2. LLM 生成 SQL 的幻觉谱系](#2. LLM 生成 SQL 的幻觉谱系)
    • [2.1 结构幻觉:不存在的对象](#2.1 结构幻觉:不存在的对象)
    • [2.2 关系幻觉:错误的 JOIN 语义](#2.2 关系幻觉:错误的 JOIN 语义)
    • [2.3 逻辑幻觉:错误的过滤与聚合](#2.3 逻辑幻觉:错误的过滤与聚合)
    • [2.4 性能幻觉:语法正确但能拖垮数据库](#2.4 性能幻觉:语法正确但能拖垮数据库)
  • [3. 治理体系总览:四层防线](#3. 治理体系总览:四层防线)
  • [4. 第一层:Schema 锚定,从源头压缩幻觉空间](#4. 第一层:Schema 锚定,从源头压缩幻觉空间)
    • [4.1 精确注入 Schema 而非让模型猜测](#4.1 精确注入 Schema 而非让模型猜测)
    • [4.2 注入真实的数据画像](#4.2 注入真实的数据画像)
    • [4.3 提供正确示例的 Few-shot 提示](#4.3 提供正确示例的 Few-shot 提示)
  • [5. 第二层:静态校验,在 SQL 离开发送前拦截](#5. 第二层:静态校验,在 SQL 离开发送前拦截)
    • [5.1 解析与白名单:只允许引用存在的对象](#5.1 解析与白名单:只允许引用存在的对象)
    • [5.2 强制注入安全约束](#5.2 强制注入安全约束)
    • [5.3 JOIN 图校验与笛卡尔积检测](#5.3 JOIN 图校验与笛卡尔积检测)
  • [6. 第三层:沙箱执行,把风险隔离在安全区](#6. 第三层:沙箱执行,把风险隔离在安全区)
    • [6.1 限定权限与只读账号](#6.1 限定权限与只读账号)
    • [6.2 资源配额与超时熔断](#6.2 资源配额与超时熔断)
    • [6.3 EXPLAIN 预检:在执行前评估代价](#6.3 EXPLAIN 预检:在执行前评估代价)
  • [7. 第四层:结果自检,兜住前面漏掉的错误](#7. 第四层:结果自检,兜住前面漏掉的错误)
    • [7.1 结构自检](#7.1 结构自检)
    • [7.2 交叉验证](#7.2 交叉验证)
  • [8. 回归与闭环:让模型从错误中学习](#8. 回归与闭环:让模型从错误中学习)
    • [8.1 错误日志与标注](#8.1 错误日志与标注)
    • [8.2 把修正后的 SQL 回流为 Few-shot 示例](#8.2 把修正后的 SQL 回流为 Few-shot 示例)
  • [9. 实用清单:接入前问自己 6 个问题](#9. 实用清单:接入前问自己 6 个问题)
  • [10. 总结](#10. 总结)

1. 问题的起点:乐观接入,悲观翻车

「给数据库套一层 LLM,用户用自然语言就能查数」------这个想法让无数团队兴奋地落地了 Text-to-SQL。Demo 跑通的瞬间,表字段自动识别、JOIN 自动推断、聚合自动补全,一切看起来都很美好。

但上线一周后,问题开始浮现:

  • 用户问「上个月的订单总额」,AI 给出的 SQL 漏了 status != 'cancelled',把已取消订单也算进去了。
  • 用户问「各部门的平均薪资」,AI 生成了一个笛卡尔积 JOIN,数据库 CPU 飙到 100%。
  • 用户问「最近新增的客户」,AI 凭空捏造了一个不存在的字段 created_at_formal

这就是 LLM 与数据库集成的核心矛盾:大模型擅长生成「看起来正确」的 SQL,却无法保证 SQL 真正正确。幻觉在自然语言里只是「说错话」,在 SQL 里就是「算错数、查慢库、写坏数据」。

本文不讨论「要不要用 LLM 查数据库」,而是讨论一个更现实的问题:当你已经决定接入 LLM,如何系统性地治理 SQL 幻觉

2. LLM 生成 SQL 的幻觉谱系

治理的前提是认清对手。LLM 生成的错误 SQL 并非随机噪声,而是有规律可循的。常见的错误类型可以划分为四类:

2.1 结构幻觉:不存在的对象

LLM 会自信地引用不存在的表、字段、函数:

sql 复制代码
-- 错误:orders 表中根本没有 shipped_at_formal 字段
SELECT shipped_at_formal FROM orders WHERE ...

这类错误源于训练数据的统计分布------模型「记住」了某些常见命名模式,并把它投射到你的具体 schema 上。

2.2 关系幻觉:错误的 JOIN 语义

把两张表 JOIN 起来很容易,JOIN 对却很难:

sql 复制代码
-- 错误:users 和 orders 应该通过 user_id 关联,而不是 email
SELECT * FROM users u
JOIN orders o ON u.email = o.customer_email

一旦 JOIN 键选错,结果要么是空集,要么是爆炸式的重复行。更隐蔽的是「JOIN 了但多一层冗余关系」,比如通过中间表间接关联时选择了错误的路径。

2.3 逻辑幻觉:错误的过滤与聚合

模型可能漏掉关键的业务规则:

  • 漏掉软删除过滤:deleted_at IS NULL
  • 漏掉状态过滤:status IN ('completed', 'refunded')
  • COUNT(DISTINCT user_id) 写成 COUNT(user_id)
  • 该用 SUM(amount) / COUNT(orders) 的地方直接用了 AVG(amount)

2.4 性能幻觉:语法正确但能拖垮数据库

有些 SQL 语法完全正确、语义也正确,但执行计划糟糕透顶:

sql 复制代码
-- 看似无害,实则对百万行大表做全表扫描
SELECT * FROM orders WHERE YEAR(created_at) = 2025;
-- 这种写法无法命中 created_at 上的索引

3. 治理体系总览:四层防线

治理 SQL 幻觉不能靠「换个更强的模型」这种单点方案。更强的模型只会降低错误率,不会消除错误。真正可靠的方案是纵深防御------让每一层各自拦截一部分错误,最终把风险压到可接受范围。
#mermaid-svg-l1E9c2eDd50y8TXD{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-l1E9c2eDd50y8TXD .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-l1E9c2eDd50y8TXD .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-l1E9c2eDd50y8TXD .error-icon{fill:#552222;}#mermaid-svg-l1E9c2eDd50y8TXD .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-l1E9c2eDd50y8TXD .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-l1E9c2eDd50y8TXD .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-l1E9c2eDd50y8TXD .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-l1E9c2eDd50y8TXD .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-l1E9c2eDd50y8TXD .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-l1E9c2eDd50y8TXD .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-l1E9c2eDd50y8TXD .marker{fill:#333333;stroke:#333333;}#mermaid-svg-l1E9c2eDd50y8TXD .marker.cross{stroke:#333333;}#mermaid-svg-l1E9c2eDd50y8TXD svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-l1E9c2eDd50y8TXD p{margin:0;}#mermaid-svg-l1E9c2eDd50y8TXD .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-l1E9c2eDd50y8TXD .cluster-label text{fill:#333;}#mermaid-svg-l1E9c2eDd50y8TXD .cluster-label span{color:#333;}#mermaid-svg-l1E9c2eDd50y8TXD .cluster-label span p{background-color:transparent;}#mermaid-svg-l1E9c2eDd50y8TXD .label text,#mermaid-svg-l1E9c2eDd50y8TXD span{fill:#333;color:#333;}#mermaid-svg-l1E9c2eDd50y8TXD .node rect,#mermaid-svg-l1E9c2eDd50y8TXD .node circle,#mermaid-svg-l1E9c2eDd50y8TXD .node ellipse,#mermaid-svg-l1E9c2eDd50y8TXD .node polygon,#mermaid-svg-l1E9c2eDd50y8TXD .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-l1E9c2eDd50y8TXD .rough-node .label text,#mermaid-svg-l1E9c2eDd50y8TXD .node .label text,#mermaid-svg-l1E9c2eDd50y8TXD .image-shape .label,#mermaid-svg-l1E9c2eDd50y8TXD .icon-shape .label{text-anchor:middle;}#mermaid-svg-l1E9c2eDd50y8TXD .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-l1E9c2eDd50y8TXD .rough-node .label,#mermaid-svg-l1E9c2eDd50y8TXD .node .label,#mermaid-svg-l1E9c2eDd50y8TXD .image-shape .label,#mermaid-svg-l1E9c2eDd50y8TXD .icon-shape .label{text-align:center;}#mermaid-svg-l1E9c2eDd50y8TXD .node.clickable{cursor:pointer;}#mermaid-svg-l1E9c2eDd50y8TXD .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-l1E9c2eDd50y8TXD .arrowheadPath{fill:#333333;}#mermaid-svg-l1E9c2eDd50y8TXD .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-l1E9c2eDd50y8TXD .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-l1E9c2eDd50y8TXD .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-l1E9c2eDd50y8TXD .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-l1E9c2eDd50y8TXD .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-l1E9c2eDd50y8TXD .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-l1E9c2eDd50y8TXD .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-l1E9c2eDd50y8TXD .cluster text{fill:#333;}#mermaid-svg-l1E9c2eDd50y8TXD .cluster span{color:#333;}#mermaid-svg-l1E9c2eDd50y8TXD div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-l1E9c2eDd50y8TXD .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-l1E9c2eDd50y8TXD rect.text{fill:none;stroke-width:0;}#mermaid-svg-l1E9c2eDd50y8TXD .icon-shape,#mermaid-svg-l1E9c2eDd50y8TXD .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-l1E9c2eDd50y8TXD .icon-shape p,#mermaid-svg-l1E9c2eDd50y8TXD .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-l1E9c2eDd50y8TXD .icon-shape .label rect,#mermaid-svg-l1E9c2eDd50y8TXD .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-l1E9c2eDd50y8TXD .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-l1E9c2eDd50y8TXD .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-l1E9c2eDd50y8TXD :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 校验失败
执行风险
结果异常
用户自然语言提问
第一层:Schema 锚定
第二层:静态校验
第三层:沙箱执行
第四层:结果自检
返回用户
修复重试
阻断并提示
标记或拒绝

4. 第一层:Schema 锚定,从源头压缩幻觉空间

LLM 幻觉的根源之一是「信息不足」。如果你只告诉模型「有一个 orders 表」,它就会用训练数据里的「平均 orders 表」来脑补字段。你给模型的 schema 信息越精确,它脑补的空间就越小

4.1 精确注入 Schema 而非让模型猜测

不要把整库几百张表的 DDL 一股脑塞给模型。应该按需检索:

python 复制代码
def build_prompt(question: str, schema_index) -> str:
    # 1. 用向量检索找出与问题最相关的表
    tables = schema_index.search(question, top_k=5)
    # 2. 仅注入这些表的结构
    schema_desc = "\n".join(
        f"表 {t.name}:{t.comment}\n"
        f"字段:{', '.join(f'{c.name} ({c.comment})' for c in t.columns)}"
        f"{';外键:' + ', '.join(t.foreign_keys) if t.foreign_keys else ''}"
        for t in tables
    )
    return PROMPT_TEMPLATE.format(schema=schema_desc, question=question)

关键不是「注入多少」,而是「注入什么」。注释和字段的业务含义比单纯的数据类型重要得多------模型看到 status (订单状态:pending/paid/cancelled/refunded) 比看到 status VARCHAR(20) 有用十倍。

4.2 注入真实的数据画像

除了结构,还可以注入量级信息:

  • 每个表的大致行数
  • 字段的基数(唯一值数量)
  • 空值比例
  • 常见枚举值的实际分布

模型看到「status 字段有 4 个取值,其中 completed 占 87%」后,就更可能正确地加上 WHERE status = 'completed' 过滤;看到「users 表 120 万行,orders 表 800 万行」后,就不太可能生成无谓的笛卡尔积。

4.3 提供正确示例的 Few-shot 提示

在 prompt 里嵌入 2-3 组「问题 → 正确 SQL」的示例,示例应覆盖你的业务中最常见的查询模式。示例如下:

复制代码
用户问:上个月注册的用户有多少?
SQL:
SELECT COUNT(*) FROM users
WHERE created_at >= DATE_TRUNC('month', CURRENT_DATE - INTERVAL '1 month')
  AND created_at < DATE_TRUNC('month', CURRENT_DATE)
  AND deleted_at IS NULL;

这种示例的价值不在于「教会」模型写 SQL,而在于示范业务规则 ------比如 deleted_at IS NULL 这个过滤必须在几乎每条查询中都出现。

5. 第二层:静态校验,在 SQL 离开发送前拦截

Schema 锚定只是降低了幻觉概率,离可靠还有距离。第二层在 SQL 生成之后、执行之前设置关卡,用确定性的程序来校验 LLM 的输出。

5.1 解析与白名单:只允许引用存在的对象

用 SQL 解析器(如 sqlglotpglastsqlparser-rs)把 LLM 生成的 SQL 解析成 AST,然后做完整性检查:

python 复制代码
import sqlglot

def validate_sql(sql: str, schema: SchemaRegistry) -> list[str]:
    errors = []
    try:
        ast = sqlglot.parse_one(sql)
    except Exception as e:
        return [f"SQL 解析失败:{e}"]

    # 检查所有引用的表是否存在
    for table in ast.find_all(sqlglot.exp.Table):
        if table.name not in schema.tables:
            errors.append(f"不存在的表:{table.name}")

    # 检查所有引用的字段是否存在
    for col in ast.find_all(sqlglot.exp.Column):
        if col.name not in schema.get_columns(col.table):
            errors.append(f"不存在的字段:{col.table}.{col.name}")

    return errors

这一步的拦截率惊人------结构幻觉(占错误的大头)几乎全部被拦下。

5.2 强制注入安全约束

对于必加的过滤条件,不要依赖模型的自觉,直接在 AST 层面强制注入:

python 复制代码
def add_mandatory_filters(ast, rules: dict[str, str]):
    """为指定表强制添加过滤条件"""
    for table_name, condition in rules.items():
        # 如果 SQL 中出现了该表但没有相应的 WHERE 条件,则注入
        if table_name in ast.find_all_tables() and not has_condition(ast, condition):
            ast = ast.where(condition)
    return ast

rules = {
    "users": "deleted_at IS NULL",
    "orders": "status != 'deleted'",
}

这样即使模型忘了写「不查已删除用户」,生成的最终 SQL 也一定带上了这个条件。

5.3 JOIN 图校验与笛卡尔积检测

在 AST 层面可以检测出危险的 JOIN 模式:

  • 多表查询但没有 JOIN 条件(笛卡尔积)
  • JOIN 键不是外键关系
  • JOIN 条件字段类型不匹配
python 复制代码
def check_join_safety(ast) -> list[str]:
    warnings = []
    if len(ast.find_all(sqlglot.exp.Table)) > 1:
        joins = ast.find_all(sqlglot.exp.Join)
        if not joins or all(j.args.get("on") is None for j in joins):
            warnings.append("多表查询缺少 JOIN 条件,存在笛卡尔积风险")
    return warnings

6. 第三层:沙箱执行,把风险隔离在安全区

前两层做的是「拦错误」,第三层做的是「拦灾难」。即使 SQL 通过了静态校验,执行时仍可能出问题------最典型的场景是 LLM 生成了 UPDATEDELETEDROP 语句。

6.1 限定权限与只读账号

这是最基础也最有效的一层。给 LLM 生成的 SQL 分配专用的只读数据库账号:

sql 复制代码
-- 创建只读用户,仅能访问必要库表
CREATE USER 'llm_readonly'@'%' IDENTIFIED BY 'xxx';
GRANT SELECT ON analytics.* TO 'llm_readonly'@'%';
-- 不授予 INSERT / UPDATE / DELETE / DROP 权限

不是「信任模型不写危险语句」,而是「即使模型写了危险语句也执行不了」。

6.2 资源配额与超时熔断

在数据库连接层设置资源限制:

python 复制代码
# MySQL 示例
cursor.execute("SET SESSION MAX_EXECUTION_TIME = 5000")  # 5 秒超时
# PostgreSQL 示例
cursor.execute("SET statement_timeout = '5s'")

同时配合连接池的超时与取消机制。一条 SQL 如果 5 秒内跑不完,大概率是执行计划有问题,直接杀掉比等它跑完划算。

6.3 EXPLAIN 预检:在执行前评估代价

对于查询类 SQL,可以先用 EXPLAIN 查看执行计划,发现风险信号就拒绝执行:

python 复制代码
def precheck_with_explain(sql: str) -> bool:
    plan = execute(f"EXPLAIN {sql}")
    # 检查是否全表扫描了超大表
    for row in plan:
        if "FULL TABLE SCAN" in row and table_row_count > 1_000_000:
            return False  # 拒绝执行
    return True

7. 第四层:结果自检,兜住前面漏掉的错误

前面三层都通过了,SQL 执行了,结果出来了------但结果可能是错的。第四层的任务是检验结果本身是否可信

7.1 结构自检

检查返回结果的形状是否符合预期:

  • 行数是否为 0 或异常大
  • 列数是否与查询意图匹配
  • 数值范围是否合理(如金额为负、年龄超过 150)
python 复制代码
def sanity_check_result(result: QueryResult) -> bool:
    if result.row_count == 0:
        return False  # 大概率 WHERE 条件写得太严
    if result.row_count > 100_000:
        return False  # 大概率丢失了必要的聚合或过滤
    for col in result.columns:
        if col.is_numeric:
            if any(v < 0 for v in col.values if v is not None) and col.name.endswith("_amount"):
                return False  # 金额不可能是负数
    return True

7.2 交叉验证

最高性价比的做法是让 LLM 用不同的方式回答同一个问题两次

  • 第一次正常生成 SQL 并执行
  • 第二次要求「用不同的 SQL 写法回答同一个问题」
  • 对比两次结果是否一致
python 复制代码
sql_a = generate_sql(question, variant="standard")
sql_b = generate_sql(question, variant="alternative")
result_a, result_b = execute(sql_a), execute(sql_b)
if compare(result_a, result_b).is_significantly_different():
    return {"confidence": "low", "note": "两次查询结果不一致,建议人工复核"}

两次独立生成的 SQL 犯同样错误的概率远低于一次生成犯错的概率------这是统计学上可靠的降错手段。

8. 回归与闭环:让模型从错误中学习

治理不只是拦截,还要让系统越来越好。每拦截到一次错误 SQL,都是一条宝贵的训练信号。

8.1 错误日志与标注

记录每一类错误:

python 复制代码
error_log = {
    "question": "上个月订单总额",
    "generated_sql": "SELECT SUM(amount) FROM orders WHERE ...",
    "error_type": "missing_status_filter",
    "error_detail": "漏掉了 status 过滤,把已取消订单也算入",
    "fixed_sql": "SELECT SUM(amount) FROM orders WHERE status != 'cancelled' AND ...",
    "timestamp": "2025-01-15T10:30:00Z",
}

8.2 把修正后的 SQL 回流为 Few-shot 示例

高频错误模式可以沉淀为新的 Few-shot 示例进入 prompt:

  • 每周分析错误日志,找出 top 3 高频错误
  • 把对应的「问题-正确 SQL」对加入提示词模板
  • 让系统在用户最常出错的地方自动学习规避

这个闭环让治理体系从「静态拦截」进化到「持续进化」,错误率会随时间单调下降。

9. 实用清单:接入前问自己 6 个问题

在把 LLM 接上数据库之前,用下面 6 个问题快速评估你的方案是否及格:

  1. Schema 是否按需注入? 还是把整库 DDL 全塞进 prompt?
  2. 有没有 SQL 解析校验环节? 还是 LLM 输出直接执行?
  3. 必加的过滤条件(如软删除)是强制注入还是靠模型自觉?
  4. 执行账号是只读的吗? 有没有超时和资源配额?
  5. 结果有异常检测吗? 还是前端拿到什么就显示什么?
  6. 错误日志有没有回流机制? 还是会重复踩同一个坑?

这六个问题对应了四层防线中的关键节点。能全部回答清楚,你的 Text-to-SQL 才不是裸奔。

10. 总结

LLM 集成数据库的幻觉治理,本质是把「对模型的不信任」转化为「工程上的确定性」。

  • Schema 锚定压缩了幻觉的生成空间;
  • 静态校验在离开发送前拦下绝大多数结构错误;
  • 沙箱执行把灾难性后果隔离在安全区;
  • 结果自检兜住语义层面的漏网之鱼;
  • 错误回流让系统持续进化。

没有任何单层方案能 100% 防住幻觉,但四层叠加后,错误率可以从「不可用」降到「可接受」,从「偶尔翻车」变成「稳定可用」。这也许不是最性感的方案,却是工程上真正可行的方案。

相关推荐
火山引擎开发者社区1 小时前
豆包大模型测评招募丨寻找行业资深 AI 实践者
人工智能
ITyunwei09871 小时前
技术管理者视角:AI 重构 ITSM 的四个工程化落点
运维·人工智能
千维百策6661 小时前
AI 软件开发中的人与智能体:软件工程循环、人在环路中与框架工程
大数据·人工智能·软件工程
专注仿真2 小时前
问答大模型技术方案算法实现-熵权法融合算法 + 交叉编码器重排算法
人工智能·python·算法·语言模型·问答大模型关键算法·熵权融合算法·交叉编码器重排算法
zcmodeltech2 小时前
工程机械与矿山机械沙盘模型多系统协同控制系统设计:基于STM32与Modbus RTU的露天开采-井下掘进-智慧矿山全场景联动方案
数据库·stm32·单片机·嵌入式硬件·制造·多分类
曹牧2 小时前
Oracle:空值排序
数据库·oracle
SelectDB2 小时前
Apache Doris 与 StarRocks 深度对比:2026 年 OLAP 引擎选型指南
数据库
阿里云大数据AI技术2 小时前
DataWorks Data Agent 实战课堂(五):AI 多模态智能数据处理
人工智能·agent