今天聊:Node.js 如何搭建自动化报表工具

3,920 阅读12分钟

前端早早聊大会,与掘金联合举办。加 codingdreamer 进大会技术群,赢在新的起跑线。


第二十七届|前端 Flutter 专场,了解 Web 渲染引擎|UI 框架|性能优化,6-5 下午直播,6 位讲师(淘宝/京东/闲鱼等),点我上车👉 (报名地址):

大会海报.png

所有往期都有全程录播,上手年票一次性解锁全部


正文如下

本文是第十五届 - 前端早早聊报表专场,也是早早聊第 107 场,来自 宋小菜-智哥 的分享。

一、SQL 是编程吗?

SQL是怎么诞生的

在讨论 SQL 是编程之前,我们先理清楚什么是 SQL,或者说 SQL 是怎么诞生的。

在远古时代,最早初代数据库有两个,一个是层次型数据库,换成今天的说法也可以叫做树型数据库,既然叫树状数据库,就和我们现在接触的树状模型差不多。

所以这个数据的弊端也是很明显的,就是实际关系中,很多实体间的关系不是一对多的,而是多对多的。

另外一个就是网状模型,相较树状模型,它可以描述现实中的复杂关系,不过这个问题也相对明显,就是这个网会变得原来越复杂,维护使用的成本会越来越高。

后来有个叫 Codd 的老博士发布一篇论文,里面讲了通过关系代数去描述数据间的关系。

那我们先看下这个关系模型是怎么描述的。

这样看上去是不是一脸懵逼,所以这个门槛很是高的。

但是我们如果翻译成这样是不是很好懂了,基本上就很接近我们自然语言了吧。

这就是 Codd 的 SQL 模型最关键的两个原则,关系代数和关系演算。一个是基于集合的运算,用现在的 SQL 表示的话就是 JOIN 操作,另一个是元组演算和域演算,就比如 > = < 这样的逻辑运算。

二、关系型数据库管理系统

然后 System R 就诞生,不过由于这是实验室的产物,所以后来 IMB 做的 DB2 这些都是后话了,但是我们可以大致窥见最早的关系型数据库是怎么来的,以及怎么实现的。

我的猜想就是底层一个文件系统,中间是关系模型,上层是解析器,最上层就是 SQL,所以我们可以得出一个结论,SQL 是一个帮助我们管理数据库文件系统的计算机语言。

好,现在我们知道什么是 SQL 了,那接下来我们看下 SQL 是否已经过时了,毕竟作为一个出来 3、4 十年的标准,很难保证他是不是已经过时了,就比如说 NoSQL 的诞生,因为现在很多数据其实都是非结构化的或者半结构化的。

但是这里有最新的编程语言排行榜,可以看到 SQL 还是排在前 10 的,这里我想的话主要是简单,其次它是声明式的,也就是写 SQL 的人不用去具体关心底层实现逻辑,只要描述清楚需要什么就可以了,参考一下身边有多少非程序员会 SQL 的数量就可以了。

三、架构演进与 SQL

接下来我想聊聊关于架构的演进与 SQL 的一些事情。

我们知道所有的应用都是从小到大,比如说一个网站,最早的时候也都是小网站,那个时候一般的架构是服务和数据库都放一起,后来慢慢的把服务和数据分离,再往后用户变多了,服务器性能开始慢慢跟不上了,这个最早是通过纵向扩展的方式来解决的,说白了就是升服务器配置。

这样做的弊端也很明显,因为服务器配置越往上升,性价比就会越来越低,其次这种做法是有极限的,后来渐渐的有了微服务的解决方式,但是你服务拆到了多个服务器上,服务的上限是提高了,可这些服务用的都是同一个数据库,数据库的性能没有提高也是白搭,后来有了分布式数据库,以及 OLAP。

分布式数据库目前一共有 3 种架构:

  1. share-disk:每一个 CPU 使用自己的私有内存区域,通过内部通讯机制直接访问所有磁盘系统;
  2. share-nothing:每一个 CPU 都有私有内存区域和私有磁盘空间,而且 2 个 CPU 不能访问相同磁盘空间, CPU 之间的通讯通过网络连接;
  3. share-memory:多个 CPU 共享同一片内存,CPU 之间通过内部通讯机制(interconnection network)进行通讯。

1 和 3 都是一台机器装做很多台机器的样子,后者是很多台机器装做 1 台机器的样子。

然后我们讲讲分布式数据库与 SQL 间的关系:

最早在 03 年的时候谷歌发了一个 Paper 叫 GFS 即 Google File System,里面就是关于谷歌内部怎么实现的一个分布式文件系统,接着在 04、06 分别发 MapReduce 和 GigTable 的 Paper,MapReduce 就是分布式计算,BigTable 就是分布式的数据管理系统。谷歌把这三架马车放出来之后,这个社区的人就很兴奋,因为终于有解决方案了,然后就照着 Paper 实现,慢慢就形成了现在的 Hadoop 生态,这里面最重要的目前就是 HDFS,也就是 GFS 的社区版,其它很多相关的东西都是以这个为基石实现的,比如 Kafka,Druid 等。

一开始用这套查数据的时候都是通过 MapReduce 来查数据,但是 MapReduce 又很复杂,你要写很多代码来实现,很多人都觉得麻烦,这个时候今天话题的主角 SQL 又参与进来了,就在 MapReduce 之上封装了一套 SQL 的实现,所以用户其实就可以通过 SQL 来写 MapReduce 的代码,这个就是我们常听说的 Hive 了。

再往后因为 MapReduce 就写在磁盘上,有人就嫌弃它慢,就搞了个 Spark,利用内存提高数据的读写速度,以及其它的优化,比如动态生成执行计划这样的操作,同样的 Spark 也实现了 SQL,调的时候用 spark.sql 就可以了。

因为最早的 Spark 只能做离线数据的加工,所以后来有了很多做实时的,不过这里面目前最活跃还是 Flink,你会发现同样的,Flink 也是支持直接写 SQL 的。

除了这些之外的,还出来了一些新的数据库和 Hive 工具,比如说 PrestoSQL/PrestoDB,同样的这类工具也是支持 SQL 的,原理和 Spark 类似,通过词法分析、语义分析、执行计划生成、优化执行计划、执行计划分段等几个步骤,让用户可以拿到自己想要的数据。link

然后看一下 TiDB 概述,TiDB 主要有三个部分组成 TiDB、TiKV 还有 PD。TiDB 你可以看做类似前面说的能跑 SQL 的 MapReduce,PD 是用来调度的,同时还是你数据库的字典,帮你管理原数据,TiKV 可以看成 HDFS。

到目前为止我们可以看到,在 OLAP 场景下,绝大多数查询任务你都可以通过 SQL 实现,那么其实对于我们来说,只要给用户一个 SQL 的输入途径,在加上一个中间层的加工,那么基本就可以满足目前绝大多数数据需求了。

四 、项目实践

前面讲完了 SQL 目前的应用,现在来讲讲项目实践。

数据类型

首先在做项目之前需要对数据有个基本概念的认知,其中最基础的数据类型的认知。现在数据类型主要分成 4 类,名称数据,顺序数据,等比数据和等距数据,等距的话,我们基本很少用到,所以这里就不讨论了。

所谓的名称数据或者说分类数据就是一堆离散没有什么逻辑关系的数据,比如城市名称,人名等,顺序数据就是在带有逻辑关系的名称数据,比如大杯/中杯/小杯或者 "2020-10-10" / "2020-10-11" 这样的时间序列,而等比数据就是身高、体重这样常用作度量的。

有了这些基本概念之后在画图表的时候你就可以更加明确我这组数据哪些字段是用作维度数据的,哪些字段是作为指标数据的。比如在一般情况下名称数据/顺序数据就可以作为 X 轴,而 Y 轴的值其实就是等比数据字段经过前面的维度聚合得出的结果。

数据存储

了解了上面的基本概念之后,再看看我们在数据存储这一块是怎么做的,一般情况下我们会把表分实体表、维表、事实表以及聚合表。

实体表顾名思义,就是我们现实中实体的数据映射,比如用户表里面就是存你的用户基本信息,一些基础属性。维表的话就是存的维度信息的表,比如城市表这样,作为维度数据。事实表是记录一些事实信息的表,比如记你的用户下单记录订单表。聚合表就是前面几种表通过指定维度聚合以及指标聚合算出来的结果表。

好了,现在到实际服务设计的部分,一般来说,做一个可视化的 SQL 编辑器的话,可以有两种方式,一种是以富文本输入框的形式做一个 Web 版 SQL Editer,直接让用户在富文本 SQL 编辑器里面写 SQL。

另外一种就是把 SQL 编程转换成 OOP,从而实现可视化 ORM 的编辑操作,因为我们可以把每个对象,比如 select 哪些字段,这样的操作直接转换成可视化的多选框之类,让用户直接操作选择。

定时任务

在有了 SQL 的输入与保存服务之后,你可能还需要一些定时任务服务,让你可以有办法拿到一些辅助数据让前端更好的实现展示与计算等。比如需要一个定时任务去同步你数据源的数据,去拿到数据源里面所有的表,以及所有的表的字段和表字段的类型等等,方便你去做你自己这个服务的数据字典,这样的话,当用户写完一个 SQL,数据源返回数据的同时,你结合你的数据字典,就知道哪些字段是顺序数据,哪些字段是名称数据,哪些字段是等比数据,哪些可以用来做维度,哪些是用来做指标的。

如果是在做可视化 ORM 的时候,会经常碰到复杂查询逻辑的情况,这个时候一般的交互很难满足用户的需求,比如 SUM(a.v1) / SUM(a.v2) 或者 CASE ... WHEN ... END 这样,你也不好直接给个 input 的框,因为容易拿到不规范的数据等情况都会出现。这个时候你就需要会写 DSL 表单,本质上是通过 CST 来实现你自己的富文本编辑器。

还有就是随着项目的表越来越多,数据源的数据也会越来越大,这个时候前端的性能就很关键了,这里的话推荐使用范式化的形式去管理你页面上的数据,你会发现页面的性能可以翻几十倍。

接着我们现在这个项目假设跑了几个月,这个时候里面的报表或者看板或者组件,可能从最开始的几个,增长到上千个。有的时候某个用户就可以拥有上百张表,那么如何让用户很好的管理他的报表或看板也是你需要考虑的事情,这里的我推荐一开始的这一块就设计成一个无限层级的菜单服务,类似于网盘那样,用户可以创建自己的文件夹,可以移动排序重命名等,类似网盘的那些操作去管理他的数据。

虽然你的用户都会写 SQL,但是每个人写 SQL 的水平是参差不齐的,这个时候你就需要一个 SQL 审核的服务对用户 SQL 进行分析,AST 解析 SQL(这里推荐用阿里的 Druid Parser),拿到用户写的 SQL 信息,比如用了多少张表,连了多少张表,连表的逻辑是否是不符合规范,再结合执行计划等对这个 SQL 进行审核和评分,避免发生什么一个 SQL 就把你整个数据库搞挂了的情况。

如果你在写项目的时候遇到一些实现上的困扰,需要找一些项目实现来参考的时候,我推荐你去跑跑看这两个,一个是 Metabase,另一个是 Superset ,因为他们都是开源的,另外 Kibana 也是很好的实践参考。


别忘了6-5 下午直播哦,点我上车👉 (报名地址):

大会海报.png

所有往期都有全程录播,上手年票一次性解锁全部


期待更多文章,点个赞