google-cloud-spanner - 使用多个“count distinct”具有巨大的性能影响
问题描述
在 Google Cloud Spanner 上,我们遇到了一些分析大量数据的查询的内存问题
GenerateArrayEvaluator ran out of memory during buffering one value
(original error message 'GenerateArrayEvaluator ran out of memory.
Requested: 9 byte(s). Already reserved: 294649856 byte(s).
Limit: 294649856 byte(s). Details: Cannot reserve 9 bytes to create a new segment
The operation HashJoinIterator is reserving the most memory (114717769 bytes).').
Requested: 0 byte(s). Already reserved: 294649856 byte(s). Limit: 294649856 byte(s).
Max Memory Operation: The operation HashJoinIterator is reserving the most memory (114717769 bytes).
我发现由于某些原因,查询正在执行非常未优化的操作。我能够隔离查询的有罪部分。所以这是重现这种情况的最小查询:
SELECT
COUNT(DISTINCT a) a,
COUNT(DISTINCT b) b
FROM foo
WHERE primary_split_key = "..."
该查询有 2 个子句COUNT(DISTINCT ...)
,这就是问题所在。它将创建一个map compute
操作,该操作将返回的行数乘以COUNT(DISTINCT ...)
select 子句中的数量。
换句话说,如果SELECT * FROM foo WHERE primary_split_key = "..."
返回 10 行,则 map 计算将生成 20 行 ( 10row * 2countDistinct
)。
如果我们有 500k 行和 3 行,count distinct
那么它将生成 150 万行。
请参阅 443k 行和 2 的查询说明COUNT(DISTINCT ...)
:
所以我们可以说这个查询的扩展性真的很差。
我们正在努力调整它以使其更好地工作。但是,我们想听听 Cloud Spanner 团队的意见:这是 spanner/count distinct 的预期行为,还是您愿意在不久的将来改进的东西?
也总是很高兴听到其他用户体验的替代方案。
编辑:我发现其他一些查询失败并显示相同错误消息的情况。但是,这些查询以这种方式显式使用函数 GENERATE_ARRAY:
SELECT *
FROM a
JOIN b ON a.id = b.id_a
LEFT JOIN UNNEST(GENERATE_ARRAY(0, a.some_number)) record
出于这个原因,我怀疑 generate_array 未优化或有内存泄漏。
解决方案
关于内存问题,根据错误消息,它似乎HashJoinIterator
是消耗最多内存的那个,它GenerateArrayEvaluator
只是由此引起的低内存情况的受害者。您的第二个查询也可能是这种情况。据推测,在您的实际查询中,您有一个哈希连接试图在一个大输入上构建一个哈希表?您是否尝试过使用提示重新执行查询join_method=apply_join
?
您发布的 count distinct 查询确实对要聚合的数据进行的传递次数与不同聚合的数量(在您的情况下为 2)一样多。虽然计划中显示的 2s 运行时间比我预期的要慢,但运行时间还取决于许多其他因素 - 您的实例的 CPU 利用率和查询的并行度,因此很难对此发表评论。
推荐阅读
- javascript - 用另一个对象多重过滤一个对象
- javascript - 为什么我的 JavaScript 代码不能在我动态添加的脚本标签中运行,但是当它作为全局变量时它可以运行?
- regex - 国际电话号码的 Ruby 正则表达式,但不包括特定的国家/地区代码
- security - 如果我想将我的服务帐户凭据存储到 GCP 的秘密管理器中以供我的应用程序使用怎么办
- html - 不能强制我的浮动 div 始终使用 CSS 在容器内居中(是的,我删除了浮动:左)
- exception - RestSharp - 在部署的应用程序中执行 API 时出现 System.Net.WebException
- java - 运行应用程序时出现 Guice / Play Evolutions / H2 数据库错误
- c# - 例外:指定的演员表无效。v
- vhdl - VHDL - 满足条件时进程不分配位
- javascript - 使用 FormData 从视频上传 base64