我的问题是假设我有一个包含 216 列的表 A :
CREATE TABLE test_data
(
fund_name varchar(255)
fund_desc varchar(255)
accountId varchar(255)
postdate date,
effectiveDate date,
businessdate Date,
activeTill TimeStamp
)
我们的用例如下:
根据全天的 kafka 事件加载数据,频繁更新表。
历史数据存储。因此每天都有数十亿行和数据不断添加。
10节点集群。
我们的数据分布有以下过滤标准:
对于所有活动记录,activeTill
的值始终为“9999-09-99,23:09:0”;accountId
计数最多可达 12k 个不同值。
查询#1:
select *
from fund_data
where postdate between '2024-06-01' and '2024-06-20'
and accountId in ('1234', '56789', '0009')
and activeTill > sysdate
查询#2:
select *
from fund_data
where effectiveDate between '2024-06-01' and '2024-06-20'
and accountId in ('1234', '56789', '0009')
and activeTill > sysdate
查询#3:
select *
from fund_data
where businessdate between '2024-06-01' and '2024-06-20'
and accountId in ('1234', '56789', '0009')
and activeTill > sysdate
在我们当前的设置中,
distkey
为 AUTO,SORT_KEY
为(postdate、accountId、sysdate)。
当在 where 子句中仅使用
postDate
时,查询性能还可以,因为它是第一个排序键。
现在,由于消费者开始平等地使用其他日期字段,这些查询的性能最差。
因此,寻找建议,在这种情况下什么是理想的 SORT 键和 DIST 键。
这是人们必须经历的常见优化改变。 如何平衡多个排序键的优化增益。 几年前我做了一次 re:Invent 演讲,其中包括了这一点,这可能会添加更多背景信息 - https://www.youtube.com/watch?v=bxfnWTiY7EM&t
这一切都归结为优化块元数据的使用。 在您的示例中,当您首先按后日期排序时,这将在使用任何其他列的数据对行进行排序之前使用此列的所有分辨率。 这意味着 postdate 的值集中在一起,导致该列的元数据值具有较小的值范围,因此在 WHERE 子句中基于该列进行查询时只需要读取几个数据块。
但是,其他日期列、 effectiveDate 和businessdate 的值将分散在整个表中。 因此,当这些列位于 WHERE 子句中时,需要从磁盘读取整个表的数据。 这可能是导致这些查询速度减慢的主要原因。 检查所有 3 种类型的查询的扫描步骤,并记下每种查询从磁盘读取的数据行数。 这可能会证实这个理论。
那么如何“平衡”所有 3 个日期列的元数据值? 您需要添加降低前 2 个排序键分辨率的列。这些“合成”列不会替换查询中使用的日期列,而仅用于对表进行排序。 (如果不清楚,请观看视频)此外,通过在名称中提供一些标识来识别这些合成列通常是一个好主意 - 例如以双下划线开头。
我建议您向表中添加 2 列 - __postdate_sortkey 和 __ effectiveDate_sortkey 并将它们用作表的第一个和第二个排序键。 第三个排序键应该是businessdate,以便这些查询也能受益。 定义 __postdate_sortkey 的一个很好的起点是 date_trunc('year', postdate) 和 __ effectiveDate_sortkey, date_trunc('month', effectiveDate)。当然,您需要分析您的性能以确保粗糙度是正确的,并且需要在对表进行清理(重新排序)和分析(更新元数据)时完成此操作。
同样,您不要更改查询 WHERE 子句。 这只是为表设置新的排序顺序,其中实际日期列的元数据为所有查询提供所需的优化。 请注意,这种查询性能的“平衡”可能会稍微影响后期查询,但总体解决方案性能将大大提高。
有一些方法可以直接检查元数据以更好地调整事物,但这可能太复杂,无法在这里快速回答。 希望不需要这种级别的优化。
希望这有帮助。