我正在尝试在最新kdb +的q中对Allen的IntersectsWith时间运算符进行基准测试。 Allen的IntersectsWith时间运算符是他定义的13个关系区间代数运算符中的11个的并集。实际上,它将返回所有重叠的间隔以及所有与间隔末尾有关的间隔。 (从这个意义上讲,它不作为原始时间运算符存在。)
我有一张表格,用于保存间隔(startDate,endDate)
上的仪器测量值-间隔的大小可以动态变化,但在下面的示例中,间隔为一分钟:
queryPeriods:dataFieldStartDate`dataFieldEndDate!(2019.01.01T00:00:00.000000000; 2019.01.02T00:00:00.000000000)
dataValues:`datafield`startDate`endDate!(`inst1_m`inst1_m`inst1_m;2019.01.01T00:00:00.000000000 2019.01.01T00:01:00.000000000 2019.01.01T00:02:00.000000000; 2019.01.01T00:01:00.000000000 2019.01.01T00:02:00.000000000 2019.01.01T00:03:00.000000000)
queryPeriods
dataFieldStartDate | dataFieldEndDate
----------------------------- -----------------------------
2019.01.01T00:00:00.000000000 | 2019.01.02T00:00:00.000000000
dataValues
datafield | startDate | endDate
--------- ----------------------------- -----------------------------
`inst1_m | 2019.01.01T00:00:00.000000000 | 2019.01.01T00:01:00.000000000
`inst1_m | 2019.01.01T00:01:00.000000000 | 2019.01.01T00:02:00.000000000
`inst1_m | 2019.01.01T00:02:00.000000000 | 2019.01.01T00:03:00.000000000
我有点熟悉wj window-join运算符,但无论如何我都不是“ q God”,而且我不确定如何在包含间隔的行上执行wj。另外,我当时想使用Relational Interval Tree数据结构对间隔进行建模,并在“叉节点”上建立索引/键控,但是后来我失去了wj的好处。
虽然这里的样本数据很小,但我的目标是最终对20B行进行基准测试。
编辑:这是一个SQL查询,该查询可复制我想做的事情以及查询的输出。您也可以run the SQL on rextester,但是由于它是使用CTE构造的,因此不需要特殊权限即可在SQL Server上运行。
;WITH QueryPeriods AS (
SELECT
DataFieldStartDate = CAST('2019.01.01 00:00:00.0000000' AS DATETIME2),
DataFieldEndDate = CAST('2019.01.02 00:00:00.0000000' AS DATETIME2)
), DataValues AS (
SELECT
datafield = 'inst1_m',
startDate = CAST('2019-01-01 00:00:00.0000000' AS DATETIME2),
endDate = CAST('2019.01.01 00:01:00.0000000' AS DATETIME2)
UNION ALL
SELECT
datafield = 'inst1_m',
startDate = CAST('2019.01.01 00:01:00.0000000' AS DATETIME2),
endDate = CAST('2019.01.01 00:02:00.0000000' AS DATETIME2)
UNION ALL
SELECT
datafield = 'inst1_m',
startDate = CAST('2019.01.01 00:02:00.0000000' AS DATETIME2),
endDate = CAST('2019.01.01 00:03:00.0000000' AS DATETIME2)
)
SELECT
qp.*,
dv.*
FROM QueryPeriods qp
LEFT JOIN DataValues dv
ON dv.datafield = 'inst1_m'
AND dv.startDate < qp.DataFieldEndDate AND dv.endDate > qp.DataFieldStartDate
输出:
DataFieldStartDate DataFieldEndDate datafield startDate endDate
01.01.2019 00:00:00 02.01.2019 00:00:00 inst1_m 01.01.2019 00:00:00
01.01.2019 00:01:00
01.01.2019 00:00:00 02.01.2019 00:00:00 inst1_m 01.01.2019 00:01:00
01.01.2019 00:02:00
01.01.2019 00:00:00 02.01.2019 00:00:00 inst1_m 01.01.2019 00:02:00
01.01.2019 00:03:00
答案 0 :(得分:2)
简单的方法(用于内存表)将仅遍历每个QueryPeriods并获取所需的数据。通常,它运行速度非常快,并且可以对其进行某些优化。
dv表(数据值)
datafield startDate endDate
----------------------------------------------
ibm 2000.01.01T00:00:03.649z 2000.01.01T00:10:03.649z
ibm 2011.01.19T12:58:59.098z 2011.01.19T13:08:59.098z
ibm 2011.01.19T12:59:08.222z 2011.01.19T13:09:08.222z
ibm 2007.11.11T21:26:07.936z 2007.11.11T21:36:07.936z
qv表(查询值)
dataFieldStartDate dataFieldEndDate
-------------------------------------------------
2011.01.19T13:08:53.604z 2011.01.19T14:09:53.604z
2007.03.05T23:46:47.997z 2007.11.11T21:26:08.938z
功能
:q) raze {[x;y]![select from dv where datafield=x,startDate<y`dataFieldEndDate,
endDate>y`dataFieldStartDate;();0b;y]}[`ibm]each qv
我在1亿行具有相同符号和2个不同查询期的表上进行了测试(上面提到的同一张表),花了3.8秒的时间来执行。
输出:
dataField startDate endDate dataFieldStartDate dataFieldEndDate
-------------------------------------------------------------------------------------------------------
ibm 2011.01.19T12:58:59.098z 2011.01.19T13:08:59.098z 2011.01.19T13:08:53.604z 2011.01.19T14:09:53.604z
ibm 2011.01.19T12:59:08.222z 2011.01.19T13:09:08.222z 2011.01.19T13:08:53.604z 2011.01.19T14:09:53.604z
ibm 2007.11.11T21:26:07.936z 2007.11.11T21:36:07.936z 2007.03.05T23:46:47.997z 2007.11.11T21:26:08.938z
优化:
表属性:在列上使用正确的属性可以帮助缩短查询执行时间。我设置了按开始日期,结束日期排序的数据值表。
并行执行:在查询之上并行运行非常容易,这也可以缩短执行时间(取决于系统配置和KDB设置)。如果您的KDB进程中正在运行从属服务器,则只需在上面的查询中使用“桃子”而不是“每个”即可。这将在不同的进程中执行不同批次的查询期。