KDB +数据库:从财务到一级方程式

KDB +是KX的产品,是一个著名的窄圆,极快的列数据库,旨在存储时间序列和基于它们的分析计算。 最初,它在金融行业中享有(并享有)极大的知名度-它被所有前十大投资银行以及许多著名的对冲基金,交易所和其他组织所使用。 最近,KX决定扩展其客户群,现在在电信,生物信息学,生产等按时间或以其他方式分类大量数据的其他领域提供解决方案。 尤其是,他们成为一级方程式阿斯顿·马丁红牛赛车队的合作伙伴,在那里他们帮助收集和处理来自汽车传感器的数据并分析风洞中的测试。 在本文中,我想告诉您KDB +的哪些功能使其具有超高的生产力,为什么公司愿意为此花大笔钱,最后,为什么它不是真正的数据库。



在本文中,我将尝试大体上说明KDB +是什么,它具有什么功能和局限性,以及对希望处理大量数据的公司的好处。 我不会详细介绍KDB +的实现及其Q编程语言的细节,这两个主题都非常广泛,应单独撰写。 可以在code.kx.com上找到许多有关这些主题的信息,包括一本关于《 Q-Q对于凡人》的书(请参阅下面的链接)。

一些条款


  • 内存数据库。 将数据存储在RAM中以便快速访问的数据库。 这样的数据库的优点是可以理解的,缺点是数据丢失的可能性,服务器上需要大量内存。
  • 列数据库。 数据按顺序存储的数据库,而不是逐条记录。 这种数据库的主要优点是,来自一列的数据一起存储在磁盘和内存中,这极大地加快了对它们的访问。 无需加载请求中未使用的列。 主要缺点是很难修改和删除记录。
  • 时间序列。 带有日期或时间等列的数据。 通常,时间排序对于此类数据很重要,因此您可以轻松确定哪个记录在当前记录之前或之后,或者应用其结果取决于记录顺序的函数。 经典数据库是基于完全不同的原理构建的-将一组记录表示为一组,但原则上未定义记录的顺序。
  • 向量 在上下文中,KDB +是具有相同原子类型(例如,数字)的元素的列表。 换句话说,是一个元素数组。 与列表不同,数组可以紧凑地存储并使用矢量处理器指令进行处理。

历史背景


KX由亚瑟·惠特尼(Arthur Whitney)于1993年创立,他曾在摩根士丹利银行(Morgan Stanley Bank)从事A +(APL的后继者)的工作,A +是金融界非常原始和流行的语言。 当然,在KX中,亚瑟(Arthur)继续本着同样的精神,并在激进极简主义的思想指导下创建了矢量功能语言K。 K个程序看起来像是一堆乱七八糟的标点符号和特殊字符,字符和功能的含义取决于上下文,并且每个操作所带的含义要比普通编程语言多得多。 因此,K程序占用最少的空间-几行可以替换诸如Java之类的冗长语言的文本页面-并且是该算法的超集中实现。

K上的一个函数,它根据给定的语法实现大多数LL1解析器生成器:

1. pp:{q:{(x;p3(),y)};r:$[-11=@x;$x;11=@x;q[`N;$*x];10=abs@@x;q[`N;x]  2.   ($)~*x;(`P;p3 x 1);(1=#x)&11=@*x;pp[{(1#x;$[2=#x;;,:]1_x)}@*x]  3.      (?)~*x;(`Q;pp[x 1]);(*)~*x;(`M;pp[x 1]);(+)~*x;(`MP;pp[x 1]);(!)~*x;(`Y;p3 x 1)  4.      (2=#x)&(@x 1)in 100 101 107 7 -7h;($[(@x 1)in 100 101 107h;`Ff;`Fi];p3 x 1;pp[*x])  5.      (|)~*x;`S,(pp'1_x);2=#x;`C,{@[@[x;-1+#x;{x,")"}];0;"(",]}({$[".sC"~4#x;6_-2_x;x]}'pp'x);'`pp];  6.   $[@r;r;($[1<#r;".s.";""],$*r),$[1<#r;"[",(";"/:1_r),"]";""]]} 

亚瑟(Arthur)还在2003年出现的KDB +中体现了这种极致效率的理念,即最小限度地移动身体(我现在很清楚字母K的名字来自何处),而无非是第四种语言K的解释器。 K以Q命名。Q还增加了对特定SQL方言(QSQL)的支持,并在解释器中增加了对将表作为系统数据类型的支持,以及用于处理内存和磁盘中的表的工具等。

因此,从用户的角度来看,KDB +只是一个Q解释器,它支持表和来自C#的类似SQL的LINQ样式的表达式。 这是KDB +与其他数据库之间最重要的区别及其主要竞争优势,而这一优势通常被忽略。 这不是禁用的数据库+辅助语言,而是功能强大的成熟编程语言+对数据库功能的内置支持。 这种差异将对列出KDB +的所有优势起决定性作用。 例如...

尺码


按照现代标准,KDB +只是微观大小。 从字面上看,这是一个小于兆字节的可执行文件,还有一个具有某些系统功能的小文本文件。 实际上-不到1兆字节,为此计划,公司每年为服务器上的一个处理器支付数万美元。

  • 这个大小使KDB +在任何硬件上都感觉良好-从Pi微型计算机到具有TB内存的服务器。 这不会以任何方式影响功能;此外,Q会立即启动,从而可以将其用作脚本语言。
  • 通过这种大小,Q解释器完全放置在处理器高速缓存中,从而加快了程序的执行速度。
  • 使用这种大小的可执行文件,Q进程占用的内存空间可以忽略不计;您可以成百上千次运行它们。 同时,如果需要,Q可以在一个进程中使用数十或数百GB的内存进行操作。

多功能性


Q非常适合各种任务。 Q进程可以用作历史数据库,并提供对TB级信息的快速访问。 例如,我们有几十个历史数据库,其中一些未经压缩的一天的数据需要超过100 GB。 但是,在合理的限制下,数据库查询将在数十到数百毫秒内执行。 通常,对于用户请求,我们有一个通用的超时时间-30秒-很少能正常工作。

同样,Q可以是内存数据库。 将新数据添加到内存中的表的速度如此之快,以至于用户查询是一个限制因素。 表中的数据存储在列中,这意味着列中的任何操作都将以最大容量使用处理器缓存。 除此之外,KX尝试通过矢量处理器指令实现所有基本操作,例如算术运算,以使其速度最大化。 Q可以执行不是数据库所特有的任务-例如,处理流数据并“实时”计算(根据任务延迟数十毫秒到几秒钟),针对不同时间间隔的金融工具提供各种汇总功能,或建立完美影响的模型交易完成后几乎立即进行市场分析。 在此类问题中,最常见的主要时间延迟不是Q,而是需要同步来自不同来源的数据。 由于处理它们的数据和函数处于同一进程中,因此实现了高速处理,并且处理减少到执行多个未解释但以二进制代码执行的QSQL表达式和联接。

最后,任何服务过程也可以用Q编写。 例如,网关进程自动将用户请求分发到必要的数据库和服务器。 程序员可以完全自由地实施任何算法,以实现平衡,优先级划分,容错,访问权限,配额以及您的内心需求。 这里的主要问题是您必须自己实现所有这些。

例如,我将列出我们拥有哪些类型的过程。 它们全部都被积极使用并协同工作,它们结合了数十种不同的数据库,处理来自许多来源的数据并为数百个用户和应用程序提供服务。

  • 数据源的连接器(馈送器)。 这些过程通常使用Q中加载的外部库。Q中的C接口非常简单,可以轻松地为任何C / C ++库创建代理函数。 Q足够快,例如可以同时处理来自所有欧洲证券交易所的FIX消息流。
  • Tickerplant分销商,充当连接器和使用者之间的中间链接。 同时,他们将输入的数据写入特殊的二进制日志中,从而为使用者提供了防止连接丢失或重新启动的能力。
  • 内存数据库(rdb)。 这些数据库提供了对原始数据的最快访问,并将它们存储在内存中。 通常,它们在白天将数据存储在表中,而在晚上将其归零。
  • 持久数据库(pdb)。 这些数据库今天在历史数据库中提供数据存储。 通常,与rdb不同,它们不将数据存储在内存中,而是在磁盘上使用特殊的缓存一天,然后在午夜将数据复制到历史数据库。
  • 历史基础(hdb)。 这些数据库提供对前几天,几个月和几年的数据的访问。 它们的大小(以天为单位)仅受硬盘驱动器大小的限制。 数据可以放置在任何地方,特别是在不同的磁盘上,以加快访问速度。 可以使用多种算法压缩数据以进行选择。 数据库结构文档齐全,操作简单,数据按单位存储在普通文件中,因此可以进行处理,包括使用操作系统。
  • 具有汇总信息的数据库。 通常按仪器名称和时间间隔将各种聚合存储在一起。 内存数据库随每条传入消息更新其状态,而历史数据库则存储预先计算的数据以加快对历史数据的访问。
  • 最后, 网关进程为应用程序和用户提供服务。 Q允许您实现传入消息的完全异步处理,在数据库之间分配它们,检查访问权限等。 我注意到,消息不限于其他大多数数据库中的SQL语句,通常不是SQL语句。 通常,SQL表达式隐藏在特殊功能中,并根据用户请求的参数进行构造-时间转换,执行过滤,数据标准化(例如,如果支付了股利,则股票价格均等)等。

一种数据类型的典型体系结构:



速度


尽管Q是一种解释语言,但它同时也是一种矢量语言。 这意味着许多内置函数(尤其是算术函数)接受任何形式的参数-数字,向量,矩阵,列表,并且程序员应将程序实现为对数组的操作。 在这种语言中,如果将一百万个元素中的两个向量相加,则解释该语言不再重要,相加将由超优化的二进制函数执行。 由于在Q程序中的大部分时间都花在了使用这些基本矢量化函数进行表的操作上,因此我们的输出速度非常快,即使在一个过程中也可以处理大量数据。 这类似于python中的数学库-尽管python本身是一种非常慢的语言,但它具有许多出色的numpy库,可让您以已编译语言的速度处理数值数据(顺便说一下,numpy在概念上接近Q)。

此外,KX非常仔细地处理了表的设计并优化了表的工作。 首先,支持多种类型的索引,这些索引由内置函数支持,不仅可以应用于表列,还可以应用于任何向量-分组,排序,唯一性属性和历史数据库的特殊分组。 索引是基本叠加的,在将元素添加到列/向量时会自动调整。 索引可以在内存和磁盘上很好地重叠表列。 执行QSQL查询时,如果可能,将自动使用索引。 其次,通过OS文件映射机制(内存映射)来处理历史数据。 大表从不加载到内存中,而是将必要的列直接映射到内存,并且实际上仅加载其中的一部分(索引在这里也有帮助)。 对于程序员而言,无论数据是否在内存中都没有区别,使用mmap的机制完全隐藏在Q的肠子中。

KDB +不是关系数据库,表可以包含任意数据,而添加新元素时表中行的顺序不会改变,并且在编写查询时可以并且应该使用。 迫切需要使用此功能来处理时间序列(来自交换,遥测,事件日志的数据),因为如果按时间对数据进行排序,则用户无需使用任何SQL技巧就可以找到表中的第一行或最后一行或N行,确定哪条线在第N条线之后,依此类推。 表的联接甚至更加简化,例如,对于16,000个事务,查找VOD.L(沃达丰)时,一个5亿个元素的表中的最后一个引用在磁盘上花费大约一秒钟,在内存中花费一毫秒。

时间联接的一个示例是将报价表映射到内存,因此无需在其中指定,隐式使用sym列上的索引以及按时间对数据进行排序的事实中指定VOD.L。 Q中的几乎所有联接都是普通函数,而不是select语句的一部分:

 1. aj[`sym`time;select from trade where date=2019.03.26, sym=`VOD.L;select from quote where date=2019.03.26] 

最后,值得注意的是,KX的工程师从亚瑟·惠特尼本人开始,就非常着迷于效率,并尽一切努力从标准Q函数中获得最大收益并优化最常用的使用模式。

总结


KDB +之所以在企业中广受欢迎,主要是由于其出色的多功能性-它既可以作为内存基础,也可以作为存储TB级历史数据的基础,也可以作为数据分析的平台。 由于数据处理直接在数据库中进行,因此可以实现较高的操作速度和资源节省。 完整的编程语言与数据库功能集成在一起,使您可以在同一平台上实现从接收数据到处理用户请求的所有必要过程堆栈。

附加信息


缺点


KDB ++ / Q的一个显着缺点是其入门阈值高。 该语言的语法很奇怪,某些功能被重载(例如,值有大约11个用例)。 最重要的是,它需要一种截然不同的编写程序的方法。 在矢量语言中,您需要始终考虑数组转换,通过map / reduce函数的几个选项(在Q中称为副词)实现所有循环,决不要试图通过用原子运算代替矢量运算来节省金钱。 例如,要查找数组中元素第N个出现的索引,请输入:

 1. (where element=vector)[N] 

尽管按照C / Java标准,这看起来效率极低(=创建一个布尔向量,在其中返回其中真实元素的索引)。 但是,这样的记录使表达式的含义更易于理解,您可以使用快速矢量运算而不是慢速原子运算。 向量语言与其他语言之间的概念差异可与命令式和功能性编程方式之间的差异相媲美,您需要为此做好准备。

一些用户也对QSQL不满意。 事实是,它看起来像真正的SQL。 实际上,它只是类SQL表达式的解释器,不支持查询优化。 用户本人必须编写最佳查询,并在Q上写许多尚未准备好的查询。 另一方面,当然,您始终可以自己编写自己的最佳查询,而不必依赖黑匣子优化器。

此外, 该公司的网站上免费提供关于Q-Q For Mortals的书籍,还有许多其他有用的材料。

另一个很大的缺点是许可证的费用。 一个CPU每年要花费数万美元。 只有大公司才能负担得起此类费用。 最近,KX使许可政策更加灵活,并提供了只为使用时间付费或在Google和Amazon云中租用KDB +的能力。 KX还提供下载用于非商业目的免费版本 (32位版本或根据要求提供64位)。

竞争者


有许多基于类似原理的专业数据库-内存中的列式数据库,专注于大量数据。 问题是这些是专门的数据库。 一个典型的例子是Clickhouse。 该数据库与KDB +在磁盘上存储数据并建立索引的原理非常相似;它执行某些查询的速度比KDB +快,尽管效果并不明显。 但是,即使Clickhouse数据库比KDB +更专业-Web分析与任意时间序列(这种差异非常重要-例如,由于这一点,在Clickhouse中无法使用记录排序)。 但是,最重要的是,Clickhouse不具有KDB +的通用性,该语言允许直接在数据库中处理数据,而不是先前将其加载到单独的应用程序中,构建任意SQL表达式,在查询中应用任意函数,创建与执行历史数据库函数无关的过程。 因此,很难将KDB +与其他数据库进行比较,它们在单独的用例中可能会更好,或者在经典数据库的任务方面会更好,但是我不知道另一个用于处理临时数据的同样有效且通用的工具。

Python整合


为了使KDB +对新手来说更容易,KX创建了可在单个过程中与Python紧密集成的库。 您可以从Q调用任何python函数,反之亦然-从Python调用任何Q函数(特别是QSQL表达式)。 必要时(出于效率考虑,并非总是如此),库会将数据从一种语言的格式转换为另一种语言的格式。 结果,Q和Python处于紧密的共生关系中,从而消除了它们之间的界限。 结果,一方面,程序员可以完全访问众多有用的Python库,另一方面,他为使用Python集成的大数据打下了快速基础,这对于参与机器学习或建模的人员尤其有用。

在Python中使用Q:

 1. >>> q() 2.q)trade:([]date:();sym:();qty:()) 3. q)\ 4. >>> q.insert('trade', (date(2006,10,6), 'IBM', 200)) 5. k(',0') 6. >>> q.insert('trade', (date(2006,10,6), 'MSFT', 100)) 7. k(',1') 

参考文献


公司网站-https://kx.com/
开发人员网站-https: //code.kx.com/v2/
Q凡人》(英语)-https://code.kx.com/q4m3/
kx员工关于KDB + / Q应用程序主题的文章-https://code.kx.com/v2/wp/

Source: https://habr.com/ru/post/zh-CN446412/


All Articles