【发布时间】:2019-06-05 07:30:39
【问题描述】:
我有一个优化问题。
我有一个表,其中包含大约 15MB 的 JSON 存储为 VARCHAR(65535) 的行。每个 JSON 字符串都是一个任意大小的数组。
- 95% 包含 16 个或更少的元素
- 最长(迄今为止)包含 67 个元素
- 硬限制是 512 个元素(在 64kB 之前不够大)
任务很简单,旋转每个数组,使每个元素都有自己的行。
id | json
----+---------------------------------------------
01 | [{"something":"here"}, {"fu":"bar"}]
=>
id | element_id | json
----+------------+---------------------------------
01 | 1 | {"something":"here"}
01 | 2 | {"fu":"bar"}
在没有任何类型的表值函数(用户定义或其他方式)的情况下,我通过加入一个数字表来进行旋转。
SELECT
src.id,
pvt.element_id,
json_extract_array_element_text(
src.json,
pvt.element_id
)
AS json
FROM
source_table AS src
INNER JOIN
numbers_table AS pvt(element_id)
ON pvt.element_id < json_array_length(src.json)
numbers 表有 512 行 (0..511),结果是正确的。
经过的时间太可怕了。它与分布或排序顺序或编码无关。这与 (我相信) redshift 的具体化有关。
处理 15MB 的 JSON 文本所需的工作内存为 7.5GB。
- 15MB *
numbers中的 512 行 = 7.5GB
如果我只在numbers 中放入 128 行,那么所需的工作内存会减少 4 倍,并且经过的时间同样会减少 (不是 4 倍,真正的查询会做其他工作,它仍在写入相同数量的结果数据等).
那么,我想知道,添加这个怎么样?
WHERE
pvt.element_id < (SELECT MAX(json_array_length(src.json)) FROM source_table)
不需要改变工作记忆,经过的时间略有增加(实际上是一个有成本但没有好处的 WHERE 子句)。
我尝试制作一个 CTE 来创建 512 个号码的列表,但没有帮助。我尝试制作一个 CTE 来创建数字列表,并使用 WHERE 子句来限制大小,但这没有帮助 (实际上 Redshift 似乎已经使用 512 行实现了,然后应用了 WHERE 子句)。
我目前的工作是为数字创建一个临时表,受 WHERE 子句的限制。在我的示例集中,这意味着我得到了一个包含 67 行的表,而不是 512 行。
这仍然不是很好,因为具有 67 个元素的 ONE 行支配了经过的时间(每一行,无论有多少元素,在应用 ON pvt.element_id < json_array_length(src.json) 之前被复制 67 次)。
我接下来的工作将分两步进行。
同上,但表格只有 16 行,并且仅适用于包含 16 个或更少元素的行
如上,使用动态混合数字表,并且仅适用于超过 16 个元素的行
问题:有人有更好的想法吗?
【问题讨论】:
-
Redshift 支持横向连接吗?
-
@a_horse_with_no_name - 没有类似于 LATERAL、APPLY、表值函数等的东西。
-
您应该在红移之外执行此操作。通过 export->process->import 或在数据到达 redshift 之前对其进行处理。
-
@JonScott - 是的,我同意。这就是中期计划(改变会产生更广泛的影响,所以不在近期计划中,特别是因为我已经“优化”到几乎可以容忍的时间尺度)。我要特别问的是,一旦数据在 Redshift 上,是否有办法更有效地做到这一点。
标签: sql json pivot amazon-redshift explode