我试图通过使用偏移量抓取某个行号来模拟BigQuery中的分页。看起来检索结果的时间会随着偏移量的增加而逐渐降低,直到遇到ResourcesExceeded
错误。以下是一些示例查询:
是否有更好的方法来使用等效的"偏移"与BigQuery没有看到性能下降?我知道这可能要求一个不存在的魔法子弹,但是想知道是否有解决方法来实现上述目标。如果没有,如果有人可以提出另一种方法来获得上述方法(例如kinetica或cassandra或其他任何方法),那将非常感激。
答案 0 :(得分:2)
BigQuery等系统的偏移通过读取和丢弃所有结果直到偏移来实现。
您需要使用列作为下限,以使引擎能够直接从键范围的那一部分开始,您不能让引擎在查询的中途随机搜索。
例如,假设您想通过费率代码,取件和下车时间查看出租车行程:
SELECT *
FROM [nyc-tlc:green.trips_2014]
ORDER BY rate_code ASC, pickup_datetime ASC, dropoff_datetime ASC
LIMIT 100
如果您通过OFFSET 100000执行此操作,则需要4秒,第一行是:
pickup_datetime: 2014-01-06 04:11:34.000 UTC
dropoff_datetime: 2014-01-06 04:15:54.000 UTC
rate_code: 1
如果不是偏移,我使用了那些日期和费率值,查询只需要2.9s:
SELECT *
FROM [nyc-tlc:green.trips_2014]
WHERE rate_code >= 1
AND pickup_datetime >= "2014-01-06 04:11:34.000 UTC"
AND dropoff_datetime >= "2014-01-06 04:15:54.000 UTC"
ORDER BY rate_code ASC, pickup_datetime ASC, dropoff_datetime ASC
limit 100
那是什么意思?然后,不是允许用户使用特定的结果#范围(例如,从100000开始的新行),而是以更自然的形式指定它(例如,2015年1月6日开始的骑行方式。
如果你想得到花哨,并且真的需要允许用户使用特定的实际行号,你可以通过提前计算行范围来提高效率,比如查询所有内容并记住开头的行号每天的小时数(8760个值),甚至几分钟(525600个值)。然后你可以用它来更好地猜测有效的开始。查找给定行范围内的最近日/分钟(例如,在Cloud Datastore中),然后将该用户查询转换为上述更高效的版本。
答案 1 :(得分:1)
正如Dan已经提到的,你需要引入一个行号。现在row_number() over ()
超出了资源。这基本上意味着你必须分开计算行的工作:
作为分区,我使用EXTRACT(month FROM pickup_datetime)
,因为它很好地分发
WITH
temp AS (
SELECT
*,
-- cumulative sum of partition sizes so we know when to start counting rows here
SUM(COALESCE(lagged,0)) OVER (ORDER BY month RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) cumulative
FROM (
-- lag partition sizes to next partition
SELECT
*,
LAG(qty) OVER (ORDER BY month) lagged
FROM (
-- get partition sizes
SELECT
EXTRACT(month FROM pickup_datetime) month,
COUNT(1) qty
FROM
`nyc-tlc.green.trips_2014`
GROUP BY
1)) )
SELECT
-- cumulative sum = last row of former partition, add to new row count
cumulative + ROW_NUMBER() OVER (PARTITION BY EXTRACT(month FROM pickup_datetime)) row,
*
FROM
`nyc-tlc.green.trips_2014`
-- import cumulative row counts
LEFT JOIN
temp
ON
(month= EXTRACT(month FROM pickup_datetime))
将其保存为新表后,您可以使用新行列进行查询而不会失去性能:
SELECT
*
FROM
`project.dataset.your_new_table`
WHERE
row BETWEEN 10000001
AND 10000100
相当麻烦,但诀窍。
答案 2 :(得分:0)
为什么不将结果表导出到GCS中?
如果您use wildcards,它会自动将表格拆分为文件,并且此导出只需要进行一次,而不是每次都查询并支付所有处理费用。
然后,您只需提供导出的文件,而不是提供对BQ API的调用结果。