文章全名:YeSQL: “You extend SQL” with Rich and Highly Performant User-Defined Functions in Relational Databases

关键词:Python,DataBase UDF,JIT

作者来自希腊大学与雅典娜研究中心,VLDB 2022的论文

文章下载地址

之前怼着YeSQL: Rich User-Defined Functions without the Overhead看了老半天,没看出啥名堂😅

那篇是Demo,这篇才是正文

相关工作

编译器(Compiler)

GraalPython:在Python中运行JVM

Numba:使用JIT加速Python Numpy运行

Pyston(该项目目前已停止维护):使用LLVM JIT加速Python

转译器(Transpilers)

Cython: Python转C

Nuitka: Python转C++

数据处理系统(Data Process System)

Tuplex: Brown University SIGMOD2021的工作

Pyspark:大名鼎鼎的Pyspark,无需多言

MonetDB(Python UDF):一个荷兰公司开发的列式数据库,在Andy的课上听到过

UDF实现方案

  • 将 UDF 转换为 SQL

    • 优点:可以实现全局UDF查询优化

    • 缺点:针对库/框架,很难支持完全成熟的语言

  • 将 UDF(和相关操作)翻译成通用中间表示法(IR)

    • 优点高级融合、循环融合、传统查询优化在一定程度上适用

    • 缺点:针对库/框架,很难支持完全成熟的语言

  • 将 UDF 嵌入数据引擎

    • 优点 现有任意代码、融合/循环融合、矢量化、函数内联等优化、JIT/LLVM 编译等性能提升工具

    • 缺点:查询优化比较棘手(仍然可行!);需要对用户代码进行分析、成本预测等

image-20241105095731856

而嵌入引擎的又分成三个流派:1.直接SQL运行 2.将UDF通过JIT预编译 3.将Query通过JIT预编译

image-20241105095944943

特性Feature

架构方案

文章将用户分为两类:Application Users(使用数据库的普通用户)和UDF developers(UDF编写人员)

一个名为CFM(Connection and Function Manager)的组件会将UDF进行预编译

如果是Server数据库(文章以MonetDB为例),就预编译后的UDF送进DBMS的线程内嵌库中(in-process embedded library)备用——对应MonetDB就是通过其CFFI连接Monet DB的C API进行调用

如果是嵌入式数据库(文章以SQlite为例),就通过Python CFFI包装SQlite API进行调用

YeSQL实现了UDF所应当具有的scalar, aggregate, table functions等功能

Python与C++代码量总计66K行,目前支持150多种UDF

UDF使用比pg-Python快68倍(回过头来看,这个比较其实不太公平😅MonetDB是列存,读取速度肯定要比pg快)

函数概览

使用了不少Python语言的内置函数(反正PyPy是JIT运行,性能不会差)

Join和Filter还是由数据库自己的执行引擎实现

举了两个SQL语句样例,解释其UDF运行的逻辑(不在这里赘述)

测试数据来源:zillow(美国房地产数据),flights(U.S. Department of Transportation Bureau of Transportation Statistics. 2020)

性能增强方案

核心在于如何避免SQL解析和Python的不匹配(mismatch)

这样的不匹配会导致两种开销:

(1)上下文切换开销,(Example:Python如果要频繁调用DBMS的API,就会有很大的调用开销)

(2)类型转换开销,涉及到类型的包装/解包,编码/解码

针对这两个问题,有5种应对方案

  1. Tracing JIT Compilation(追踪即时编译)
  2. 无缝与DBMS衔接
  3. UDF融合(Fusion)
  4. 并行化
  5. 状态化UDF

Tracing JIT Compilation

使用PyPy就自带Tracing JIT Compilation,这点不需要在工程上特别实现

Tracing JIT(即时追踪编译)是一种动态代码优化技术,专注于识别并优化程序中最常执行的路径,也称为“热路径”。它的特点是不会直接编译整个函数或方法,而是动态追踪并记录代码的执行过程,锁定这些频繁执行的路径并将它们编译成高效的机器码。这样,在这些路径再次执行时,程序可以直接运行优化后的代码,显著提升运行速度。

Tracing JIT的工作过程:

  1. 追踪阶段:Tracing JIT 首先解释执行代码,动态追踪代码的执行流,并找到一些频繁运行的路径或循环。这种追踪通常在检测到某段代码多次执行时启动。

  2. 记录执行路径:在追踪热路径时,JIT 会记录下路径中的每个操作、变量的值和类型等信息,形成一条“路径”。

  3. 编译热路径:一旦锁定热路径,JIT 会将该路径编译为高效的机器码。因为仅编译了热点代码路径,编译过程可以更快、更高效,且编译器可以针对该路径进行深入优化。

  4. 优化后的执行:当程序再次进入热路径时,JIT 会直接运行已经编译好的机器码,而不再重新解释执行,从而大幅提升执行效率。

  5. 回退与去优化:如果发现新的代码执行情况不符合之前的路径假设(比如类型变化),JIT 会“去优化”(deoptimization),回到解释器模式并可能重新追踪新的路径。

示例

PyPy(针对Python)和LuaJIT(针对Lua)是典型的Tracing JIT实现。它们通过锁定并优化高频路径,将这些解释性语言的性能大幅提升。

Tracing JIT 的主要优势在于,它能够精准地将编译工作集中在最耗时的路径上,实现高效的代码执行。这对于带有大量循环的程序尤其有效,因为这些循环的执行频率高、路径固定,能获得显著的性能提升。

这里跑个题:有意思的点在于,Chrome V8虽然也能热路径优化,但却属于Method-based JIT

Tracing JIT 适合优化具有稳定循环和执行路径的程序,而 V8 则通过函数级别的编译方式,适应 JavaScript 的动态特性,更加灵活且能覆盖整个函数的优化需求。因此,尽管 V8 和 Tracing JIT 都会进行去优化和类型假设,但 V8 不属于 Tracing JIT,因为它不聚焦于追踪特定路径,而是优化整个方法。

Java的Hotspot其实也具备Tracing JIT Compilation的特性,也不属于Tracing JIT Compilation的范畴

因此,虽然 HotSpot JVM 有类似 Tracing JIT 的“热点检测”和去优化机制,但它并不属于 Tracing JIT,而是更倾向于方法级别的 JIT 编译,通过分层编译和方法优化来提升 Java 程序的整体性能。

无缝与DBMS衔接

可以理解为:使用C API,当然你想的话直接开发个DBMS,把你开发的UDF特性写进去也不是不行😆

UDF融合(Fusion)

这里上两张作者团队在SEBD2023(PDF下载链接放后面的参考资料中)的PPT,看起来简单易懂😁这不就是内联函数么

image-20241104222424877

image-20241104222702987

并行化

Pypy虽然也有GIL锁,但在CFFI转换期间GIL会懒惰释放,所以并行化不会有问题,不需要在工程上特别实现,Pass

状态化UDF

用空间换时间的方案:存储函数的上下文,从而加速调用速度

这里放一张我做的组会PPT

image-20241104224050628

虽然这名字有点唬人😂但本质就是函数上下文存储

Evaluation评估

SEBD2023的PPT的34-37页讲了些基本的实验细节

image-20241104224421584

但跟主要的内容还是对于性能增强方案的评估

image-20241104224915522

这里我不得不提到这张图,虽然之前Demo里也有这张图,但直到本文才对这张图进行了解释

这其中有的方案,按特定顺序可以实现1+1>2的效果

比如:

在 JIT 之前应用Parallelism不会产生很好的效果,而且在Parallelism和JIT前实现UDF Fusion就可能失去动态优化

因此建议执行路线是UDF Fusion -> JIT -> Parallelism

在JIT之前矢量化(Vectorization)会更好,可以减少动态跟踪所需的指令

Tracing JIT Compilation

实验结果表明:PyPy执行UDF的速度是CPython的3倍,Cython的1.7倍

Nuitka和Numba虽然也比CPython的执行分别快2.4倍于与1.9倍,但依然没有YeSQL快

image-20241104231526485

Seamless integration with a DBMS

和原生SQL比较,使用80M flights数据,YeSQL会快上1.4倍

image-20241104231239178

(这里图没处理好,灰色柱子是Numpy,远慢于两者)

image-20241104231646476

Multithread

文章设置了一个很复杂的实验

涉及到冷/热缓存,固态/机械硬盘读取/共享内存读取

实验在列式数据库上实现

YeSQL多线程的速度是Tuplex的1.56到3.37倍

且Tuplex受缓存的影响特别大,而YeSQL则没有这个问题。

image-20241105083752624

UDF Fusion

测试用的SQL语句,三个UDF函数嵌套

select extractnumber(lower(remove_small_words(text))) from texts;

UDF在处理字符串的问题上效益会更好

Parallelism

文章说多线程YeSQL相比较于单线程YeSQL有50%的提升,但真按图中显示只有33%的提升

虽然但是,原本单线程的YeSQL就比MonetDB自带的CPython与Vectorized化后的Numpy快上几倍

image-20241105084714506

Stateful UDFs

基于Zillow数据衡量

这一段篇幅不大,但需要结合前边内容看

前边的方案开启了Stateful,运行只需要7秒

后面的则没有开启Stateful,运行需要14.6秒

image-20241105085517179

Resource Usage

与tuplex和Pyspark对比,内存占用是三者当中最低的同时,CPU使用率要比Tuplex好

image-20241105090004311

Code Review

Code: https://github.com/athenarc/YeSQL/

使用说明指南:https://athenarc.github.io/YeSQL/

运行在Pypy2.7(Note:虽然Python2已经被废弃,但Pypy2.7截止到2024.08.22还是可是维护状态)当中,Server-Base的话使用CFFI与系统交互,Embedded直接使用API(多半也是C/C++ API)

在排除了PyPy和MonetDB安装包后,项目结构目录如下:

YeSQL/
|-- README.md
|-- Specs.md
|-- YeSQL_MonetDB
|   |-- cffi_wrappers
|   |   |-- createfuncs.sql
|   |   |-- libwrappedudfs.so
|   |   `-- udfs.h
|   |-- functions
|   |   |-- __init__.py
|   |   |-- aggregate
|   |   |   |-- __init__.py
|   |   |   |-- date.py
|   |   |   |-- graph.py
|   |   |   |-- jpacks.py
|   |   |   |-- mining.py
|   |   |   |-- partialsort.py
|   |   |   |-- selection.py
|   |   |   |-- setpath.py
|   |   |   |-- skcluster.py
|   |   |   |-- skdimred.py
|   |   |   |-- statistics.py
|   |   |   |-- subgroup.py
|   |   |   |-- text.py
|   |   |   `-- util.py
|   |   |-- conf.py
|   |   |-- row
|   |   |   |-- __init__.py
|   |   |   |-- boolean.py
|   |   |   |-- date.py
|   |   |   |-- evals.py
|   |   |   |-- fileops.py
|   |   |   |-- formating.py
|   |   |   |-- htmlops.py
|   |   |   |-- iptools.py
|   |   |   |-- jpacks.py
|   |   |   |-- langtools.py
|   |   |   |-- logparse.py
|   |   |   |-- mathops.py
|   |   |   |-- setpath.py
|   |   |   |-- settings.py
|   |   |   |-- similarity.py
|   |   |   |-- stopwords.py
|   |   |   |-- stringdist.py
|   |   |   |-- termsetops.py
|   |   |   |-- testing
|   |   |   |   `-- sales.tsv
|   |   |   |-- text.py
|   |   |   |-- tzconverter.py
|   |   |   |-- util.py
|   |   |   `-- variables.py
|   |   |-- setpath.py
|   |   |-- sqltransform.py
|   |   `-- vtable
|   |       |-- __init__.py
|   |       |-- cache.py
|   |       |-- clipboard.py
|   |       |-- clipout.py
|   |       |-- coltypes.py
|   |       |-- continue.py
|   |       |-- dirfiles.py
|   |       |-- examplevt.py
|   |       |-- exec.py
|   |       |-- expand.py
|   |       |-- file.py
|   |       |-- flow.py
|   |       |-- fromeav.py
|   |       |-- hidden.py
|   |       |-- jsonpipe.py
|   |       |-- mysql.py
|   |       |-- oaiget.py
|   |       |-- oracle.py
|   |       |-- ordered.py
|   |       |-- output.py
|   |       |-- pipe.py
|   |       |-- postgres.py
|   |       |-- queryplan.py
|   |       |-- range.py
|   |       |-- rowidvt.py
|   |       |-- sample.py
|   |       |-- setpath.py
|   |       |-- setschema.py
|   |       |-- skpredict.py
|   |       |-- sktrain.py
|   |       |-- slidingwindow.py
|   |       |-- sqlite.py
|   |       |-- stdinput.py
|   |       |-- testing
|   |       |   |-- GeoIPCountryCSV.zip
|   |       |   |-- colpref.csv
|   |       |   |-- colpref.tsv
|   |       |   |-- colpref.tsv.gz
|   |       |   |-- colpref.zip
|   |       |   |-- internalflow.sql
|   |       |   |-- testflow.sql
|   |       |   |-- testtable.sql
|   |       |   `-- topflow.sql
|   |       |-- timeslidingwindow.py
|   |       |-- toeav.py
|   |       |-- unindexed.py
|   |       |-- unionalldb.py
|   |       |-- variables.py
|   |       |-- vtbase.py
|   |       |-- vtiterable.py
|   |       |-- vtout.py
|   |       |-- webtable.py
|   |       |-- whilevt.py
|   |       `-- xmlparse.py
|   |-- functionslocal
|   |   |-- __init__.py
|   |   |-- aggregate
|   |   |   `-- __init__.py
|   |   |-- row
|   |   |   `-- __init__.py
|   |   `-- vtable
|   |       `-- __init__.py
|   |-- lib
|   |   |-- LM
|   |   |   |-- DisabledLMs
|   |   |   |   |-- afrikaans.lm
|   |   |   |   |-- amharic-utf.lm
|   |   |   |   |-- arabic-iso8859_6.lm
|   |   |   |   |-- arabic-windows1256.lm
|   |   |   |   |-- basque.lm
|   |   |   |   |-- breton.lm
|   |   |   |   |-- catalan.lm
|   |   |   |   |-- chinese-big5.lm
|   |   |   |   |-- chinese-gb2312.lm
|   |   |   |   |-- drents.lm
|   |   |   |   |-- esperanto.lm
|   |   |   |   |-- frisian.lm
|   |   |   |   |-- greek-iso8859-7.lm
|   |   |   |   |-- greek-windows1253.lm
|   |   |   |   |-- hebrew-iso8859_8.lm
|   |   |   |   |-- hindi.lm
|   |   |   |   |-- indonesian.lm
|   |   |   |   |-- irish.lm
|   |   |   |   |-- japanese-euc_jp.lm
|   |   |   |   |-- japanese-shift_jis.lm
|   |   |   |   |-- korean.lm
|   |   |   |   |-- malay.lm
|   |   |   |   |-- manx.lm
|   |   |   |   |-- marathi.lm
|   |   |   |   |-- middle_frisian.lm
|   |   |   |   |-- mingo.lm
|   |   |   |   |-- nepali.lm
|   |   |   |   |-- persian.lm
|   |   |   |   |-- quechua.lm
|   |   |   |   |-- rumantsch.lm
|   |   |   |   |-- sanskrit.lm
|   |   |   |   |-- scots.lm
|   |   |   |   |-- scots_gaelic.lm
|   |   |   |   |-- swahili.lm
|   |   |   |   |-- tagalog.lm
|   |   |   |   |-- tamil.lm
|   |   |   |   |-- thai.lm
|   |   |   |   |-- ukrainian-koi8_r.lm
|   |   |   |   |-- vietnamese.lm
|   |   |   |   |-- welsh.lm
|   |   |   |   `-- yiddish-utf.lm
|   |   |   |-- albanian.lm
|   |   |   |-- armenian.lm
|   |   |   |-- belarus-windows1251.lm
|   |   |   |-- bosnian.lm
|   |   |   |-- bulgarian-iso8859_5.lm
|   |   |   |-- croatian-ascii.lm
|   |   |   |-- czech-iso8859_2.lm
|   |   |   |-- danish.lm
|   |   |   |-- dutch.lm
|   |   |   |-- english.lm
|   |   |   |-- estonian.lm
|   |   |   |-- finnish.lm
|   |   |   |-- french.lm
|   |   |   |-- georgian.lm
|   |   |   |-- german.lm
|   |   |   |-- greek-utf.lm
|   |   |   |-- hungarian.lm
|   |   |   |-- icelandic.lm
|   |   |   |-- italian.lm
|   |   |   |-- latin.lm
|   |   |   |-- latvian.lm
|   |   |   |-- lithuanian.lm
|   |   |   |-- norwegian.lm
|   |   |   |-- polish.lm
|   |   |   |-- portuguese.lm
|   |   |   |-- romanian.lm
|   |   |   |-- russian-iso8859_5.lm
|   |   |   |-- russian-koi8_r.lm
|   |   |   |-- russian-windows1251.lm
|   |   |   |-- serbian-ascii.lm
|   |   |   |-- slovak-ascii.lm
|   |   |   |-- slovak-windows1250.lm
|   |   |   |-- slovenian-ascii.lm
|   |   |   |-- slovenian-iso8859_2.lm
|   |   |   |-- spanish.lm
|   |   |   |-- swedish.lm
|   |   |   `-- turkish.lm
|   |   |-- TableHTMLParser.py
|   |   |-- __init__.py
|   |   |-- argsparse.py
|   |   |-- boolops.py
|   |   |-- chardet
|   |   |   |-- __init__.py
|   |   |   |-- big5freq.py
|   |   |   |-- big5prober.py
|   |   |   |-- chardistribution.py
|   |   |   |-- charsetgroupprober.py
|   |   |   |-- charsetprober.py
|   |   |   |-- codingstatemachine.py
|   |   |   |-- constants.py
|   |   |   |-- docs
|   |   |   |   |-- css
|   |   |   |   |   `-- chardet.css
|   |   |   |   |-- faq.html
|   |   |   |   |-- history.html
|   |   |   |   |-- how-it-works.html
|   |   |   |   |-- images
|   |   |   |   |   |-- caution.png
|   |   |   |   |   |-- important.png
|   |   |   |   |   |-- note.png
|   |   |   |   |   |-- permalink.gif
|   |   |   |   |   |-- tip.png
|   |   |   |   |   `-- warning.png
|   |   |   |   |-- index.html
|   |   |   |   |-- license.html
|   |   |   |   |-- supported-encodings.html
|   |   |   |   `-- usage.html
|   |   |   |-- escprober.py
|   |   |   |-- escsm.py
|   |   |   |-- eucjpprober.py
|   |   |   |-- euckrfreq.py
|   |   |   |-- euckrprober.py
|   |   |   |-- euctwfreq.py
|   |   |   |-- euctwprober.py
|   |   |   |-- gb2312freq.py
|   |   |   |-- gb2312prober.py
|   |   |   |-- hebrewprober.py
|   |   |   |-- jisfreq.py
|   |   |   |-- jpcntx.py
|   |   |   |-- langbulgarianmodel.py
|   |   |   |-- langcyrillicmodel.py
|   |   |   |-- langgreekmodel.py
|   |   |   |-- langhebrewmodel.py
|   |   |   |-- langhungarianmodel.py
|   |   |   |-- langthaimodel.py
|   |   |   |-- latin1prober.py
|   |   |   |-- mbcharsetprober.py
|   |   |   |-- mbcsgroupprober.py
|   |   |   |-- mbcssm.py
|   |   |   |-- sbcharsetprober.py
|   |   |   |-- sbcsgroupprober.py
|   |   |   |-- sjisprober.py
|   |   |   |-- test.py
|   |   |   |-- universaldetector.py
|   |   |   `-- utf8prober.py
|   |   |-- collections26.py
|   |   |-- colorama
|   |   |   |-- LICENSE.txt
|   |   |   |-- __init__.py
|   |   |   |-- ansi.py
|   |   |   |-- ansitowin32.py
|   |   |   |-- initialise.py
|   |   |   |-- win32.py
|   |   |   `-- winterm.py
|   |   |-- conutils.py
|   |   |-- dateutil
|   |   |   |-- LICENSE
|   |   |   |-- __init__.py
|   |   |   |-- easter.py
|   |   |   |-- parser.py
|   |   |   |-- relativedelta.py
|   |   |   |-- rrule.py
|   |   |   |-- tz.py
|   |   |   |-- tzwin.py
|   |   |   `-- zoneinfo
|   |   |       |-- __init__.py
|   |   |       `-- zoneinfo-2010g.tar.gz
|   |   |-- dsv.py
|   |   |-- fastavro
|   |   |   |-- NOTICE.txt
|   |   |   |-- PKG-INFO
|   |   |   |-- __init__.py
|   |   |   |-- __main__.py
|   |   |   |-- reader.py
|   |   |   |-- six.py
|   |   |   `-- writer.py
|   |   |-- gtable.py
|   |   |-- gzip32.py
|   |   |-- gzip34.py
|   |   |-- htmlentities.py
|   |   |-- inoutparsing.py
|   |   |-- ipaddr.py
|   |   |-- iso8601.py
|   |   |-- iterutils.py
|   |   |-- jaydebeapi
|   |   |   |-- COPYING.LESSER
|   |   |   |-- __init__.py
|   |   |   `-- dbapi2.py
|   |   |-- jdbc
|   |   |   `-- readme.txt
|   |   |-- jopts.py
|   |   |-- jsonpath.py
|   |   |-- kdtree.py
|   |   |-- listser.py
|   |   |-- madcomp.py
|   |   |-- memoize.py
|   |   |-- pg8000
|   |   |   |-- __init__.py
|   |   |   |-- dbapi.py
|   |   |   |-- errors.py
|   |   |   |-- interface.py
|   |   |   |-- protocol.py
|   |   |   |-- types.py
|   |   |   `-- util.py
|   |   |-- porter.py
|   |   |-- porter2.py
|   |   |-- pptable.py
|   |   |-- pymysql
|   |   |   |-- __init__.py
|   |   |   |-- charset.py
|   |   |   |-- connections.py
|   |   |   |-- constants
|   |   |   |   |-- CLIENT.py
|   |   |   |   |-- COMMAND.py
|   |   |   |   |-- ER.py
|   |   |   |   |-- FIELD_TYPE.py
|   |   |   |   |-- FLAG.py
|   |   |   |   |-- SERVER_STATUS.py
|   |   |   |   `-- __init__.py
|   |   |   |-- converters.py
|   |   |   |-- cursors.py
|   |   |   |-- err.py
|   |   |   |-- times.py
|   |   |   `-- util.py
|   |   |-- pyparsing.py
|   |   |-- pyperclip.py
|   |   |-- pyreadline
|   |   |   |-- __init__.py
|   |   |   |-- clipboard
|   |   |   |   |-- __init__.py
|   |   |   |   `-- win32_clipboard.py
|   |   |   |-- configuration
|   |   |   |   |-- pyreadlineconfig.ini
|   |   |   |   `-- startup.py
|   |   |   |-- console
|   |   |   |   |-- __init__.py
|   |   |   |   |-- ansi.py
|   |   |   |   |-- console.py
|   |   |   |   |-- console_attributes.py
|   |   |   |   |-- consolebase.py
|   |   |   |   |-- event.py
|   |   |   |   `-- ironpython_console.py
|   |   |   |-- error.py
|   |   |   |-- get_doc.py
|   |   |   |-- keysyms
|   |   |   |   |-- __init__.py
|   |   |   |   |-- common.py
|   |   |   |   |-- keysyms.py
|   |   |   |   `-- winconstants.py
|   |   |   |-- lineeditor
|   |   |   |   |-- __init__.py
|   |   |   |   |-- history.py
|   |   |   |   |-- lineobj.py
|   |   |   |   `-- wordmatcher.py
|   |   |   |-- logger.py
|   |   |   |-- logserver.py
|   |   |   |-- modes
|   |   |   |   |-- __init__.py
|   |   |   |   |-- basemode.py
|   |   |   |   |-- emacs.py
|   |   |   |   |-- notemacs.py
|   |   |   |   `-- vi.py
|   |   |   |-- release.py
|   |   |   |-- rlmain.py
|   |   |   `-- unicode_helper.py
|   |   |-- readme.txt
|   |   |-- reimport.py
|   |   |-- schemaUtils.py
|   |   |-- setpath.py
|   |   |-- simpleutils.py
|   |   |-- sqlitetypes.py
|   |   |-- sqlparse
|   |   |   |-- __init__.py
|   |   |   |-- engine
|   |   |   |   |-- __init__.py
|   |   |   |   |-- filter.py
|   |   |   |   `-- grouping.py
|   |   |   |-- filters.py
|   |   |   |-- formatter.py
|   |   |   |-- keywords.py
|   |   |   |-- lexer.py
|   |   |   |-- sql.py
|   |   |   `-- tokens.py
|   |   |-- stopwordlist.py
|   |   |-- stringdists.py
|   |   |-- textcat.py
|   |   |-- unicodeops.py
|   |   |-- vtoutgtable.py
|   |   |-- winunicode.py
|   |   `-- ziputils.py
|   `-- monetdb.py
|-- YeSQLite
|   |-- LICENSE.txt
|   |-- demo
|   |   |-- continents.tsv
|   |   `-- countries.tsv
|   |-- docs
|   |   |-- builddocs.sh
|   |   |-- generate_function_doc.py
|   |   |-- html
|   |   |   `-- readme.txt
|   |   `-- source
|   |       |-- _static
|   |       |   |-- jsMath
|   |       |   |   |-- blank.gif
|   |       |   |   |-- easy
|   |       |   |   |   `-- load.js
|   |       |   |   |-- extensions
|   |       |   |   |   |-- AMSmath.js
|   |       |   |   |   |-- AMSsymbols.js
|   |       |   |   |   |-- HTML.js
|   |       |   |   |   |-- autobold.js
|   |       |   |   |   |-- bbox.js
|   |       |   |   |   |-- boldsymbol.js
|   |       |   |   |   |-- double-click.js
|   |       |   |   |   |-- eqn-number.js
|   |       |   |   |   |-- fbox.js
|   |       |   |   |   |-- font.js
|   |       |   |   |   |-- leaders.js
|   |       |   |   |   |-- mathchoice.js
|   |       |   |   |   |-- mimeTeX.js
|   |       |   |   |   |-- moreArrows.js
|   |       |   |   |   |-- newcommand.js
|   |       |   |   |   |-- underset-overset.js
|   |       |   |   |   `-- verb.js
|   |       |   |   |-- jsMath-BaKoMa-fonts.js
|   |       |   |   |-- jsMath-autoload.html
|   |       |   |   |-- jsMath-controls.html
|   |       |   |   |-- jsMath-easy-load.js
|   |       |   |   |-- jsMath-fallback-mac-mozilla.js
|   |       |   |   |-- jsMath-fallback-mac-msie.js
|   |       |   |   |-- jsMath-fallback-mac.js
|   |       |   |   |-- jsMath-fallback-pc.js
|   |       |   |   |-- jsMath-fallback-symbols.js
|   |       |   |   |-- jsMath-fallback-unix.js
|   |       |   |   |-- jsMath-global-controls.html
|   |       |   |   |-- jsMath-global.html
|   |       |   |   |-- jsMath-loader-omniweb4.js
|   |       |   |   |-- jsMath-loader-post.html
|   |       |   |   |-- jsMath-loader.html
|   |       |   |   |-- jsMath-msie-mac.js
|   |       |   |   |-- jsMath-old-browsers.js
|   |       |   |   |-- jsMath.js
|   |       |   |   |-- local
|   |       |   |   |   `-- macros.js
|   |       |   |   |-- plugins
|   |       |   |   |   |-- CHMmode.js
|   |       |   |   |   |-- autoload.js
|   |       |   |   |   |-- global.js
|   |       |   |   |   |-- mimeTeX.js
|   |       |   |   |   |-- noCache.js
|   |       |   |   |   |-- noGlobal.js
|   |       |   |   |   |-- noImageFonts.js
|   |       |   |   |   |-- smallFonts.js
|   |       |   |   |   |-- spriteImageFonts.js
|   |       |   |   |   `-- tex2math.js
|   |       |   |   |-- test
|   |       |   |   |   |-- index-images.html
|   |       |   |   |   |-- index.html
|   |       |   |   |   |-- jsMath40.jpg
|   |       |   |   |   `-- sample.html
|   |       |   |   `-- uncompressed
|   |       |   |       |-- def.js
|   |       |   |       |-- font.js
|   |       |   |       |-- jsMath-fallback-mac.js
|   |       |   |       |-- jsMath-fallback-pc.js
|   |       |   |       |-- jsMath-fallback-symbols.js
|   |       |   |       |-- jsMath-fallback-unix.js
|   |       |   |       `-- jsMath.js
|   |       |   `-- madis-screen.png
|   |       |-- about.txt
|   |       |-- conf.py
|   |       |-- examples.txt
|   |       |-- extending.txt
|   |       |-- index.txt
|   |       |-- install.txt
|   |       |-- license.txt
|   |       |-- madislog.png
|   |       |-- manual.txt
|   |       |-- modules.txt
|   |       |-- people.txt
|   |       |-- quickstart.txt
|   |       |-- thanks.txt
|   |       |-- usefulnotes.txt
|   |       |-- vtablehowto.txt
|   |       `-- workflows.txt
|   |-- examples
|   |   |-- citeseer
|   |   |   `-- cite.sql
|   |   |-- dblp
|   |   |   `-- dblp.sql
|   |   |-- diavgeia
|   |   |   |-- diavgeia.sql
|   |   |   `-- diavgeiaget.py
|   |   `-- readme.txt
|   |-- functions
|   |   |-- __init__.py
|   |   |-- aggregate
|   |   |   |-- __init__.py
|   |   |   |-- date.py
|   |   |   |-- graph.py
|   |   |   |-- jpacks.py
|   |   |   |-- mining.py
|   |   |   |-- partialsort.py
|   |   |   |-- selection.py
|   |   |   |-- setpath.py
|   |   |   |-- skcluster.py
|   |   |   |-- skdimred.py
|   |   |   |-- statistics.py
|   |   |   |-- subgroup.py
|   |   |   |-- text.py
|   |   |   `-- util.py
|   |   |-- conf.py
|   |   |-- row
|   |   |   |-- __init__.py
|   |   |   |-- boolean.py
|   |   |   |-- date.py
|   |   |   |-- evals.py
|   |   |   |-- fileops.py
|   |   |   |-- formating.py
|   |   |   |-- htmlops.py
|   |   |   |-- iptools.py
|   |   |   |-- jpacks.py
|   |   |   |-- langtools.py
|   |   |   |-- logparse.py
|   |   |   |-- mathops.py
|   |   |   |-- setpath.py
|   |   |   |-- settings.py
|   |   |   |-- similarity.py
|   |   |   |-- stopwords.py
|   |   |   |-- stringdist.py
|   |   |   |-- termsetops.py
|   |   |   |-- testing
|   |   |   |   `-- sales.tsv
|   |   |   |-- text.py
|   |   |   |-- tzconverter.py
|   |   |   |-- util.py
|   |   |   `-- variables.py
|   |   |-- setpath.py
|   |   |-- sqltransform.py
|   |   `-- vtable
|   |       |-- __init__.py
|   |       |-- cache.py
|   |       |-- clipboard.py
|   |       |-- clipout.py
|   |       |-- coltypes.py
|   |       |-- continue.py
|   |       |-- dirfiles.py
|   |       |-- examplevt.py
|   |       |-- exec.py
|   |       |-- expand.py
|   |       |-- file.py
|   |       |-- flow.py
|   |       |-- fromeav.py
|   |       |-- hidden.py
|   |       |-- jsonpipe.py
|   |       |-- mysql.py
|   |       |-- oaiget.py
|   |       |-- oracle.py
|   |       |-- ordered.py
|   |       |-- output.py
|   |       |-- pipe.py
|   |       |-- postgres.py
|   |       |-- queryplan.py
|   |       |-- range.py
|   |       |-- rowidvt.py
|   |       |-- sample.py
|   |       |-- setpath.py
|   |       |-- setschema.py
|   |       |-- skpredict.py
|   |       |-- sktrain.py
|   |       |-- slidingwindow.py
|   |       |-- sqlite.py
|   |       |-- stdinput.py
|   |       |-- testing
|   |       |   |-- GeoIPCountryCSV.zip
|   |       |   |-- colpref.csv
|   |       |   |-- colpref.tsv
|   |       |   |-- colpref.tsv.gz
|   |       |   |-- colpref.zip
|   |       |   |-- internalflow.sql
|   |       |   |-- testflow.sql
|   |       |   |-- testtable.sql
|   |       |   `-- topflow.sql
|   |       |-- timeslidingwindow.py
|   |       |-- toeav.py
|   |       |-- unindexed.py
|   |       |-- unionalldb.py
|   |       |-- variables.py
|   |       |-- vtbase.py
|   |       |-- vtiterable.py
|   |       |-- vtout.py
|   |       |-- webtable.py
|   |       |-- whilevt.py
|   |       `-- xmlparse.py
|   |-- functionslocal
|   |   |-- __init__.py
|   |   |-- aggregate
|   |   |   `-- __init__.py
|   |   |-- row
|   |   |   `-- __init__.py
|   |   `-- vtable
|   |       `-- __init__.py
|   |-- lib
|   |   |-- LM
|   |   |   |-- DisabledLMs
|   |   |   |   |-- afrikaans.lm
|   |   |   |   |-- amharic-utf.lm
|   |   |   |   |-- arabic-iso8859_6.lm
|   |   |   |   |-- arabic-windows1256.lm
|   |   |   |   |-- basque.lm
|   |   |   |   |-- breton.lm
|   |   |   |   |-- catalan.lm
|   |   |   |   |-- chinese-big5.lm
|   |   |   |   |-- chinese-gb2312.lm
|   |   |   |   |-- drents.lm
|   |   |   |   |-- esperanto.lm
|   |   |   |   |-- frisian.lm
|   |   |   |   |-- greek-iso8859-7.lm
|   |   |   |   |-- greek-windows1253.lm
|   |   |   |   |-- hebrew-iso8859_8.lm
|   |   |   |   |-- hindi.lm
|   |   |   |   |-- indonesian.lm
|   |   |   |   |-- irish.lm
|   |   |   |   |-- japanese-euc_jp.lm
|   |   |   |   |-- japanese-shift_jis.lm
|   |   |   |   |-- korean.lm
|   |   |   |   |-- malay.lm
|   |   |   |   |-- manx.lm
|   |   |   |   |-- marathi.lm
|   |   |   |   |-- middle_frisian.lm
|   |   |   |   |-- mingo.lm
|   |   |   |   |-- nepali.lm
|   |   |   |   |-- persian.lm
|   |   |   |   |-- quechua.lm
|   |   |   |   |-- rumantsch.lm
|   |   |   |   |-- sanskrit.lm
|   |   |   |   |-- scots.lm
|   |   |   |   |-- scots_gaelic.lm
|   |   |   |   |-- swahili.lm
|   |   |   |   |-- tagalog.lm
|   |   |   |   |-- tamil.lm
|   |   |   |   |-- thai.lm
|   |   |   |   |-- ukrainian-koi8_r.lm
|   |   |   |   |-- vietnamese.lm
|   |   |   |   |-- welsh.lm
|   |   |   |   `-- yiddish-utf.lm
|   |   |   |-- albanian.lm
|   |   |   |-- armenian.lm
|   |   |   |-- belarus-windows1251.lm
|   |   |   |-- bosnian.lm
|   |   |   |-- bulgarian-iso8859_5.lm
|   |   |   |-- croatian-ascii.lm
|   |   |   |-- czech-iso8859_2.lm
|   |   |   |-- danish.lm
|   |   |   |-- dutch.lm
|   |   |   |-- english.lm
|   |   |   |-- estonian.lm
|   |   |   |-- finnish.lm
|   |   |   |-- french.lm
|   |   |   |-- georgian.lm
|   |   |   |-- german.lm
|   |   |   |-- greek-utf.lm
|   |   |   |-- hungarian.lm
|   |   |   |-- icelandic.lm
|   |   |   |-- italian.lm
|   |   |   |-- latin.lm
|   |   |   |-- latvian.lm
|   |   |   |-- lithuanian.lm
|   |   |   |-- norwegian.lm
|   |   |   |-- polish.lm
|   |   |   |-- portuguese.lm
|   |   |   |-- romanian.lm
|   |   |   |-- russian-iso8859_5.lm
|   |   |   |-- russian-koi8_r.lm
|   |   |   |-- russian-windows1251.lm
|   |   |   |-- serbian-ascii.lm
|   |   |   |-- slovak-ascii.lm
|   |   |   |-- slovak-windows1250.lm
|   |   |   |-- slovenian-ascii.lm
|   |   |   |-- slovenian-iso8859_2.lm
|   |   |   |-- spanish.lm
|   |   |   |-- swedish.lm
|   |   |   `-- turkish.lm
|   |   |-- TableHTMLParser.py
|   |   |-- __init__.py
|   |   |-- argsparse.py
|   |   |-- boolops.py
|   |   |-- chardet
|   |   |   |-- __init__.py
|   |   |   |-- big5freq.py
|   |   |   |-- big5prober.py
|   |   |   |-- chardistribution.py
|   |   |   |-- charsetgroupprober.py
|   |   |   |-- charsetprober.py
|   |   |   |-- codingstatemachine.py
|   |   |   |-- constants.py
|   |   |   |-- docs
|   |   |   |   |-- css
|   |   |   |   |   `-- chardet.css
|   |   |   |   |-- faq.html
|   |   |   |   |-- history.html
|   |   |   |   |-- how-it-works.html
|   |   |   |   |-- images
|   |   |   |   |   |-- caution.png
|   |   |   |   |   |-- important.png
|   |   |   |   |   |-- note.png
|   |   |   |   |   |-- permalink.gif
|   |   |   |   |   |-- tip.png
|   |   |   |   |   `-- warning.png
|   |   |   |   |-- index.html
|   |   |   |   |-- license.html
|   |   |   |   |-- supported-encodings.html
|   |   |   |   `-- usage.html
|   |   |   |-- escprober.py
|   |   |   |-- escsm.py
|   |   |   |-- eucjpprober.py
|   |   |   |-- euckrfreq.py
|   |   |   |-- euckrprober.py
|   |   |   |-- euctwfreq.py
|   |   |   |-- euctwprober.py
|   |   |   |-- gb2312freq.py
|   |   |   |-- gb2312prober.py
|   |   |   |-- hebrewprober.py
|   |   |   |-- jisfreq.py
|   |   |   |-- jpcntx.py
|   |   |   |-- langbulgarianmodel.py
|   |   |   |-- langcyrillicmodel.py
|   |   |   |-- langgreekmodel.py
|   |   |   |-- langhebrewmodel.py
|   |   |   |-- langhungarianmodel.py
|   |   |   |-- langthaimodel.py
|   |   |   |-- latin1prober.py
|   |   |   |-- mbcharsetprober.py
|   |   |   |-- mbcsgroupprober.py
|   |   |   |-- mbcssm.py
|   |   |   |-- sbcharsetprober.py
|   |   |   |-- sbcsgroupprober.py
|   |   |   |-- sjisprober.py
|   |   |   |-- test.py
|   |   |   |-- universaldetector.py
|   |   |   `-- utf8prober.py
|   |   |-- collections26.py
|   |   |-- colorama
|   |   |   |-- LICENSE.txt
|   |   |   |-- __init__.py
|   |   |   |-- ansi.py
|   |   |   |-- ansitowin32.py
|   |   |   |-- initialise.py
|   |   |   |-- win32.py
|   |   |   `-- winterm.py
|   |   |-- conutils.py
|   |   |-- dateutil
|   |   |   |-- LICENSE
|   |   |   |-- __init__.py
|   |   |   |-- easter.py
|   |   |   |-- parser.py
|   |   |   |-- relativedelta.py
|   |   |   |-- rrule.py
|   |   |   |-- tz.py
|   |   |   |-- tzwin.py
|   |   |   `-- zoneinfo
|   |   |       |-- __init__.py
|   |   |       `-- zoneinfo-2010g.tar.gz
|   |   |-- dsv.py
|   |   |-- fastavro
|   |   |   |-- NOTICE.txt
|   |   |   |-- PKG-INFO
|   |   |   |-- __init__.py
|   |   |   |-- __main__.py
|   |   |   |-- reader.py
|   |   |   |-- six.py
|   |   |   `-- writer.py
|   |   |-- gtable.py
|   |   |-- gzip32.py
|   |   |-- gzip34.py
|   |   |-- htmlentities.py
|   |   |-- inoutparsing.py
|   |   |-- ipaddr.py
|   |   |-- iso8601.py
|   |   |-- iterutils.py
|   |   |-- jaydebeapi
|   |   |   |-- COPYING.LESSER
|   |   |   |-- __init__.py
|   |   |   `-- dbapi2.py
|   |   |-- jdbc
|   |   |   `-- readme.txt
|   |   |-- jopts.py
|   |   |-- jsonpath.py
|   |   |-- kdtree.py
|   |   |-- listser.py
|   |   |-- madcomp.py
|   |   |-- memoize.py
|   |   |-- pg8000
|   |   |   |-- __init__.py
|   |   |   |-- dbapi.py
|   |   |   |-- errors.py
|   |   |   |-- interface.py
|   |   |   |-- protocol.py
|   |   |   |-- types.py
|   |   |   `-- util.py
|   |   |-- porter.py
|   |   |-- porter2.py
|   |   |-- pptable.py
|   |   |-- pymysql
|   |   |   |-- __init__.py
|   |   |   |-- charset.py
|   |   |   |-- connections.py
|   |   |   |-- constants
|   |   |   |   |-- CLIENT.py
|   |   |   |   |-- COMMAND.py
|   |   |   |   |-- ER.py
|   |   |   |   |-- FIELD_TYPE.py
|   |   |   |   |-- FLAG.py
|   |   |   |   |-- SERVER_STATUS.py
|   |   |   |   `-- __init__.py
|   |   |   |-- converters.py
|   |   |   |-- cursors.py
|   |   |   |-- err.py
|   |   |   |-- times.py
|   |   |   `-- util.py
|   |   |-- pyparsing.py
|   |   |-- pyperclip.py
|   |   |-- pyreadline
|   |   |   |-- __init__.py
|   |   |   |-- clipboard
|   |   |   |   |-- __init__.py
|   |   |   |   `-- win32_clipboard.py
|   |   |   |-- configuration
|   |   |   |   |-- pyreadlineconfig.ini
|   |   |   |   `-- startup.py
|   |   |   |-- console
|   |   |   |   |-- __init__.py
|   |   |   |   |-- ansi.py
|   |   |   |   |-- console.py
|   |   |   |   |-- console_attributes.py
|   |   |   |   |-- consolebase.py
|   |   |   |   |-- event.py
|   |   |   |   `-- ironpython_console.py
|   |   |   |-- error.py
|   |   |   |-- get_doc.py
|   |   |   |-- keysyms
|   |   |   |   |-- __init__.py
|   |   |   |   |-- common.py
|   |   |   |   |-- keysyms.py
|   |   |   |   `-- winconstants.py
|   |   |   |-- lineeditor
|   |   |   |   |-- __init__.py
|   |   |   |   |-- history.py
|   |   |   |   |-- lineobj.py
|   |   |   |   `-- wordmatcher.py
|   |   |   |-- logger.py
|   |   |   |-- logserver.py
|   |   |   |-- modes
|   |   |   |   |-- __init__.py
|   |   |   |   |-- basemode.py
|   |   |   |   |-- emacs.py
|   |   |   |   |-- notemacs.py
|   |   |   |   `-- vi.py
|   |   |   |-- release.py
|   |   |   |-- rlmain.py
|   |   |   `-- unicode_helper.py
|   |   |-- readme.txt
|   |   |-- reimport.py
|   |   |-- schemaUtils.py
|   |   |-- setpath.py
|   |   |-- simpleutils.py
|   |   |-- sqlitetypes.py
|   |   |-- sqlparse
|   |   |   |-- __init__.py
|   |   |   |-- engine
|   |   |   |   |-- __init__.py
|   |   |   |   |-- filter.py
|   |   |   |   `-- grouping.py
|   |   |   |-- filters.py
|   |   |   |-- formatter.py
|   |   |   |-- keywords.py
|   |   |   |-- lexer.py
|   |   |   |-- sql.py
|   |   |   `-- tokens.py
|   |   |-- stopwordlist.py
|   |   |-- stringdists.py
|   |   |-- textcat.py
|   |   |-- unicodeops.py
|   |   |-- vtoutgtable.py
|   |   |-- winunicode.py
|   |   `-- ziputils.py
|   |-- libexternal
|   |   `-- __init__.py
|   |-- mexec.py
|   |-- mterm.py
|   |-- pypylib
|   |   |-- apsw.py
|   |   |-- apsw.py.bak
|   |   |-- msgpack
|   |   |   |-- COPYING
|   |   |   |-- __init__.py
|   |   |   |-- _version.py
|   |   |   |-- exceptions.py
|   |   |   `-- fallback.py
|   |   `-- readme.txt
|   |-- tests
|   |   `-- readme.txt
|   `-- yesql.py
|-- data
|   |-- GlobalAirportDatabase.txt
|   |-- L_CARRIER_HISTORY.csv
|   |-- flights.csv
|   |-- loaddata_sqlite.sql
|   |-- loadflights.sql
|   |-- loadschema.sql
|   `-- zillow.csv
|-- exec.sh
|-- sql_queries
|   |-- flights.sql
|   |-- flights_sqlite.sql
|   |-- zillow.sql
|   `-- zillow_sqlite.sql
`-- udfs
    |-- __init__.py
    |-- flights.py
    `-- zillow.py

对于YeSQL-SQLite的实现,使用了CFFI修改apsw库,再通过apsw库实现udf及后续的操作

个人评价

Really interesting!😀很多我在Demo想问的问题在这里都找到了答案

每个实验结果都能在理论当中找到对应的部分

不过Python3.13还是3.14计划引入JIT并去除GIL锁,不知道那时候YeSQL是否还能跑的更快

这个组在ICDE 2023和VLDB 2023有后续进展,值得后续跟进

参考资料

https://sebd2023.dei.unipd.it/

https://www.youtube.com/watch?v=NDPqO1o4Ba8