kdb+x是Kx Systems公司新发布的产品,它对SQL的支持分为两方面,一是通过q命令行工具执行,二是通过在Python中执行。
一、获取并安装kdb+x
登录https://kdb-x.kx.com/sign-in,填写电子邮件地址,就能登录获取下载地址,也可以在线安装,页面上提供许可码,同时也会发邮件。
我使用下载安装方式,安装包地址就不贴出来了,因为地址是动态的,和登录用户的会话绑定。
离线安装命令行为
unzip l64arm-bundle.zip && bash install_kdb.sh --offline --b64lic BASE64许可码
注意这里有个问题。进行到验证安装阶段,安装脚本提示
-------- Verifying installation --------
Error: Installation verification failed: q binary missing or not executable
-------- Installation failed - Rolling back changes --------
然后就恢复到未安装状态了。
解决这个问题的办法是用文本编辑器打开install_kdb.sh,从中找到verify_installation || perform_rollback
一行,把它删除或注释掉,即
# verify_installation || perform_rollback
然后重新执行离线安装命令行,就能安装完成。安装位置在/用户home目录/.kx/bin:$PATH
如果需要在任意目录执行,将它加入搜索路径,例如
export PATH="/root/.kx/bin:$PATH"
还建议安装rlwrap,然后将下面行加入用户配置脚本
alias q="rlwrap -r q
二、在q命令行执行SQL语句
输入q,就进去交互命令行界面,提示符是q),q命令可直接输入,比如
til(10)
输出
0 1 2 3 4 5 6 7 8 9
要执行SQL,只要在相应的语句前加s)前缀。比如:(注意这里q)是提示符,不需要用户输入)
建表
q)s)CREATE TABLE tripsFare (vendor varchar,fare float)
`tripsFare
插入2行
q)s)INSERT INTO tripsFare(vendor,fare) values ('CMT',100),('didi',200)
查询
q)s)select * from tripsFare
vendor fare
-----------
CMT 100
didi 200
kdb+x具体支持的SQL类型参考文档
三、在python命令行执行SQL语句
首先安装python包pykx,命令行如下
python3 /par/pip.pyz install --pre pykx --break-system-packages -i https://pypi.tuna.tsinghua.edu.cn/simple
我是因为docker环境安装pip太麻烦,就用了pip.pyz,访问pypi网站很慢,就用了清华源镜像。如果你的环境有pip,访问pypi网站也很快,那么,
pip install --pre pykx
即可。
安装完成后,下载教学包,里面有python做时间序列分析的示例,也提到了SQL写法,摘录如下。
先把stocks.csv解压缩到/par。
>>> import pykx as kx
>>> kx.q.til(10)
pykx.LongVector(pykx.q('0 1 2 3 4 5 6 7 8 9'))
>>> from datetime import date
>>> import numpy as np
>>> import os
>>> import psutil
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'psutil'
>>> from pathlib import Path
>>> with open('/par/stocks.txt', 'r') as f:
... py_symbols = f.read().split('\n')
...
>>> syms = kx.random.random(100, py_symbols)
>>> n = 20000000;
>>> day = date(2025, 1, 1);
>>> trade = kx.Table(data = {
... 'time': day + kx.random.random(n, kx.q('24:00:00')),
... 'sym': kx.random.random(n, syms),
... 'price': kx.random.random(n, 100.0),
... 'size': kx.random.random(n, 1000)
... }
... ).sort_values('time')
>>> trade.dtypes
pykx.Table(pykx.q('
columns datatypes
--------------------------
time "kx.TimestampAtom"
sym "kx.SymbolAtom"
price "kx.FloatAtom"
size "kx.LongAtom"
'))
生成了2000万行
>>> len(trade)
20000000
>>> trade.head(10)
pykx.Table(pykx.q('
time sym price size
-------------------------------------------------
2025.01.01D00:00:00.000000000 SAVA 86.12543 644
2025.01.01D00:00:00.000000000 JAMF 16.51214 828
2025.01.01D00:00:00.000000000 TBBK 10.68305 327
2025.01.01D00:00:00.000000000 WVVIP 89.58529 990
2025.01.01D00:00:00.000000000 LGCL 38.29104 904
2025.01.01D00:00:00.000000000 MNST 40.16916 264
2025.01.01D00:00:00.000000000 DSWL 70.14543 633
2025.01.01D00:00:00.000000000 APCX 32.23879 629
2025.01.01D00:00:00.000000000 KPLT 18.70299 276
2025.01.01D00:00:00.000000000 SOXQ 51.78228 408
'))
下面是等价SQL语句
>>> kx.q.sql("SELECT * FROM $1 LIMIT 10", trade)
pykx.Table(pykx.q('
time sym price size
-------------------------------------------------
2025.01.01D00:00:00.000000000 SAVA 86.12543 644
2025.01.01D00:00:00.000000000 JAMF 16.51214 828
2025.01.01D00:00:00.000000000 TBBK 10.68305 327
2025.01.01D00:00:00.000000000 WVVIP 89.58529 990
2025.01.01D00:00:00.000000000 LGCL 38.29104 904
2025.01.01D00:00:00.000000000 MNST 40.16916 264
2025.01.01D00:00:00.000000000 DSWL 70.14543 633
2025.01.01D00:00:00.000000000 APCX 32.23879 629
2025.01.01D00:00:00.000000000 KPLT 18.70299 276
2025.01.01D00:00:00.000000000 SOXQ 51.78228 408
'))
注意上述sql,表名用$1代替,然后trade是实际的pykx表名。其他值也可以用变量占位符替换。比如
>>> kx.q.sql("SELECT * FROM $1 where price < $2 LIMIT 2", trade,50)
pykx.Table(pykx.q('
time sym price size
-------------------------------------------------
2025.01.01D00:00:00.000000000 JAMF 16.51214 828
2025.01.01D00:00:00.000000000 TBBK 10.68305 327
'))