9

1 引言

clipboard.png

对时序数据的处理有两种方式,如图所示,右边是 SQL,左边是自定义查询语言,也称为 NoSQL,处于中间地带的称为 SQL-LIKE 语言。

本文通过对比 SQL 阵营的 TimescaleDB 与 NoSQL 阵营的 InfluxDB,试图给出一些对比。

2 概述

TimescaleDB

TimescaleDB 完全接受了 SQL 语法,因此几乎没有什么学习门槛,更通过可视化操作优化了使用方式。

InfluxDB

InfluxDB 创造了一种新的查询语言,这里是 Flux 文法.(了解更多文法相关知识,可以移步 精读《手写 SQL 编译器 - 文法介绍》

InfluxDB 为什么创造 Flux 语法

InfluxDB 之所以创造 Flux 语法,而不使用 SQL,主要有两个原因:

  1. 更强的查询功能:SQL 无法轻松完成时序查询。
  2. 时间序列的查询需要基于流的函数模型,而不是 SQL 的代数模型。

所谓流模型,就类似 JS 函数式编程中类似概念:

source.pipe(
  map(x => x + x),
  mergeMap(...),
  filter(...)
)

更强的查询功能?

InfluxDB 拿下面例子举例:

Flux:

from(db:"telegraf")
  |> range(start:-1h)
  |> filter(fn: (r) => r._measurement == "foo")
  |> exponentialMovingAverage(size:-10s)

SQL:

select id,
       temp,
       avg(temp) over (partition by group_nr order by time_read) as rolling_avg
from (
  select id,
         temp,
         time_read,
         interval_group,
         id - row_number() over (partition by interval_group order by time_read) as group_nr
  from (
     select id,
            time_read,
            'epoch'::timestamp + '900 seconds'::interval * (extract(epoch from time_read)::int4 / 900) as interval_group,
            temp
     from readings
  ) t1
) t2
order by time_read;

虽然看上去 SQL 写法比 Flux 长了不少,但其实 Flux 代码的核心在于实现了自定义函数 exponentialMovingAverage,而 PostgreSQL 也有 创建函数 的能力。

通过 SQL 定义一个自定义函数:

CREATE OR REPLACE FUNCTION exponential_moving_average_sfunc
(state numeric, next_value numeric, alpha numeric)
RETURNS numeric LANGUAGE SQL AS
$$
SELECT
         CASE
                WHEN state IS NULL THEN next_value
                ELSE alpha * next_value + (1-alpha) * state
         END
$$;
CREATE AGGREGATE exponential_moving_average(numeric, numeric)
(sfunc = exponential_moving_average_sfunc, stype = numeric);

之后可以像 Flux 函数一样的调用:

SELECT time,
       exponential_moving_average(value, 0.5) OVER (ORDER BY time)
FROM telegraph
WHERE measurement = 'foo' and time > now() - '1 hour';

可见从函数定义上也和 Flux 打成平手,作者认为既然功能相同,而基于 SQL 的语言学习成本更低,所以不需要创造一个新的语言。

关于语法糖与 SQL 标准

作者认为,虽然有观点认为,Flux 的语法糖比 SQL 更简洁,但代码的可维护性并不是行数越少越好,而是是否容易被人类理解。

对于创造一个函数标准可能破坏 SQL 的可移植性,作者认为那也比完全创造一个新语法要强。

基于流的函数模型强于 SQL 代数模型?

诚然,从功能角度来看,当然函数模型强于代数模型,因为代数模型只是在描述事物,而不能精准控制执行的每一步。

但我们要弄清楚 SQL 的场景,是通过描述一个无顺序的查询问题,让数据库给出结果。而在查询过程中,数据库可以对 SQL 语句作出一些优化。

反观函数模型,是在用业务代码描述查询请求,这种代码是无法被自动优化的,虽然为用户提供了更底层的控制,但其代价是无法被数据库执行引擎所优化。

如果你更看中查询语言,而不是具体执行逻辑,SQLl 依然是最好的选择。

3 总结

之所以制作这一期精读,是为了探索 SQL 与其他查询语言的关系,去理解为什么 SQL 沿用至今。

SQL 与其他函数类查询语言不在一个层面上,如果用语法糖、可操纵性抨击 SQL,只能得出看似正确,实则荒谬的结论。

SQL 是一个查询语言,与普通编程语言相比,它还在上层,最终会转化为关系代数执行,但关系代数会遵循一些等价的转换规律,比如交换律、结合律、过滤条件拆分等等,通过预估每一步的时间开销,将 SQL 执行顺序重新组合,可以提高执行效率。

如果有多个 SQL 同时执行,还可以整合成一个或多个新的 SQL,合并重复的查询请求。

在数据驱动商业的今天,SQL 依然是数据查询最通用的解决方案。

4 更多讨论

讨论地址是:精读《SQL vs Flux》 · Issue #96 · dt-fe/weekly

如果你想参与讨论,请点击这里,每周都有新的主题,周末或周一发布。


黄子毅
7k 声望9.5k 粉丝