Ianus Inferus/地狱门神

Exoptatus infera advenisti.

View on GitHub Go Back

SQL的存在意义

Ianus Inferus

2026-05-24

最近看到一些关于SQL难以被vibe的说法,产生了一些想法。

在大学学习SQL的时候,就觉得SQL是一个很不好的语言。

也有一些对于SQL的改进想法,例如关系代数算子,GraphQuery,但并非非常成功,主流数据库仍然没有放弃SQL语言。

但是,对于异构计算来说,GPU上的计算现在非常成功,尤其是像CUDA、Pytorch这样的执行引擎。

实际上,数据库上的计算和显卡上的计算没有区别,也可以用类似的思想来实现。

将计算过程写成一个有向无环图(DAG),每个结点表示一个算子,类似于编译过程中语义阶段产生的每个函数的计算步骤构成的有向无环图一样。算子包括读取、写入、映射、笛卡尔积等不同的操作。再将图序列化传给数据库服务器,由服务器进行JIT,再执行。需要高性能的情况下,可将图进行AOT。

以下为一个示例图,说明如何通过DAG来表示一个计算过程。

从一个用户登录记录表计算用户总数,以及7日活跃数、30日活跃数,并且提取登录次数最多的前20名用户。
digraph G {
    // 基础设置
    rankdir=HV;
    node [shape=box, style="filled, rounded", fontname="Arial"];
    compound=true;

    // 数据源节点
    subgraph cluster_sources {
        label = "Data Sources";
        color = lightgrey;
        login_records [label="Source: login_records", fillcolor="#e1f5fe"];
    }

    // 中间变量/算子
    logins_map [label="Map: {user_id, time}", fillcolor="#fff9c4"];
    
    // 支流 A: 活跃统计
    stats_agg [label="Aggregate:\l- count_distinct(all)\l- filter(7d).count()\l- filter(30d).count()", fillcolor="#c8e6c9"];
    
    // 支流 B: Top 20
    group_by_user [label="Group By: user_id", fillcolor="#fff9c4"];
    count_agg [label="Aggregate: count()", fillcolor="#c8e6c9"];
    sort_node [label="Sort: desc(count)", fillcolor="#ffccbc"];
    take_node [label="Take: 20", fillcolor="#ffccbc"];

    // 最终汇聚
    result_sink [label="Result Sink\n(Summary + Details)", fillcolor="#d1c4e9", shape=penta];

    // 逻辑连接
    login_records -> logins_map;
    
    // 分支点
    logins_map -> stats_agg [label="Branch A"];
    logins_map -> group_by_user [label="Branch B"];
    
    // 支流 B 的后续
    group_by_user -> count_agg;
    count_agg -> sort_node;
    sort_node -> take_node;

    // 汇聚到结果
    stats_agg -> result_sink;
    take_node -> result_sink;
}

代码

// 1. 定义数据源(节点)
val raw_logins = Source("login_records")

// 2. 提取公共中间变量(分流点)
val logins = raw_logins.map(r -> {user_id: r.user_id, time: r.login_time})

// 3. 支流 A:计算多维活跃指标(利用 Lambda 灵活处理)
val stats = logins.aggregate(
    total_users = count_distinct(u -> u.user_id),
    active_7d   = count_distinct(u -> u.user_id).filter(u -> u.time > now - 7d),
    active_30d  = count_distinct(u -> u.user_id).filter(u -> u.time > now - 30d)
)

// 4. 支流 B:计算排行榜(逻辑并行,互不干扰)
val top_20 = logins
    .group_by(u -> u.user_id)
    .aggregate(count = count())
    .sort_by(desc(u -> u.count))
    .take(20)

// 5. 汇聚结果(Sink)
return Result(summary = stats, details = top_20)

总结:数据库也应使用有向无环算子图的形式来进行计算。

Go Back