在 Redshift 中使用连接的最佳方式

Posted

技术标签:

【中文标题】在 Redshift 中使用连接的最佳方式【英文标题】:Optimal way of using joins in Redshift 【发布时间】:2017-07-27 13:27:22 【问题描述】:

我在 AWS redshift 中有 2 个表。详情如下

a) 展示次数(计算特定广告的展示次数)

    行数(1.7 亿) 分发密钥(ad_campaign) 排序键(created_on)

b) 点击次数(计算特定广告的点击次数)。

    行数(8000 万) 分发密钥(ad_campaign) 排序键(created_on)

我有一个带有 2 个切片的 DC1 大型集群。

我正在尝试运行以下查询

select impressions.offer_id, count(imp_cnt) from 
  bidsflyer.tblImpressionLog_Opt impressions
full join bidsflyer.tblTrackingLinkLog_Opt clicks
  on impressions.offer_id=clicks.offer_id and date_trunc('week', 
impressions.created_on)=date_trunc('week', clicks.created_on)
  where impressions.created_on >= '2017-07-27 00:00:00'
  group by 1

此查询需要 8 分钟以上才能运行。考虑到数据量,我认为这是相当大的,我觉得数据量并不大。

查询计划如下所示

XN HashAggregate  (cost=2778257688268.43..2778257688268.60 rows=67 width=12)
      ->  XN Hash Left Join DS_DIST_NONE  (cost=179619.84..2778170875920.65 rows=17362469555 width=12)

    Hash Cond: (("outer".offer_id = "inner".offer_id) AND (date_trunc('week'::text, "outer".created_on) = date_trunc('week'::text, "inner".created_on)))

  ->  XN Seq Scan on tblimpressionlog_opt impressions  (cost=0.00..724967.36 rows=57997389 width=20)
          Filter: (created_on >= '2017-07-27 00:00:00'::timestamp without time zone)

  ->  XN Hash  (cost=119746.56..119746.56 rows=11974656 width=12)
          ->  XN Seq Scan on tbltrackinglinklog_opt clicks  (cost=0.00..119746.56 rows=11974656 width=12)

谁能指导我正确使用分配键和排序键。

我应该如何设计我的查询?

【问题讨论】:

如果速度是重中之重,我强烈建议您使用至少 2 个节点。 【参考方案1】:

表设置:

1) 按照计划,最昂贵的操作是按offer_id分组。这是有道理的,因为您没有按 offer_id 对数据进行排序或分发。您的表非常大,因此您可以通过(offer_id,created_on) 使用交错排序键重新创建表(交错键应该为包含的列赋予相等且与顺序无关的权重,并且已知对较大的表有积极影响)。

2) 如果您按周加入,您可以具体化您的周列(创建一个物理列并用date_trunc 输出填充它)。这可能会为您节省一些计算工作,以便在连接期间动态获取这些值。但是,此操作很便宜,如果您的表已经按时间戳列排序,Redshift 可能已经只扫描了适当的块。此外,如果每个报价运行时间很短(意味着报价列具有高基数并且与时间列具有高相关性),您可以通过 (offer_id,week_created) 使用复合排序键,这将允许合并连接,即更快,而且聚合也很快。

3) 如果您在其他查询中不使用ad_campaign,您可以通过offer_id 分配这两个表。在分布键中加入连接列是一种很好的做法,您的查询不太可能从中受益,因为您只有一个节点并且分布方式主要影响多节点设置。

所有建议都只是假设,不知道数据的确切性质,它们需要运行基准测试(使用推荐的配置创建表、复制数据、清理、分析、运行相同的查询至少 3 次,并将时间与原始设置)。如果您这样做并在此处发布结果,我将不胜感激。

RE 查询本身,您可以将FULL JOIN 替换为JOIN,因为您不需要它。 FULL JOIN 应该用于不仅要获得两个表格的交集,还要获得没有相关点击的展示,反之亦然。情况似乎并非如此,因为您按impressions.created_on 过滤并按impressions.offer_id 分组。所以,你所需要的只是路口。用简单的JOIN 替换FULL JOIN 也可能会影响查询性能。如果您想查看点击次数为零的优惠,可以使用LEFT JOIN

【讨论】:

【参考方案2】:

Merge join 比 hash join 快,你应该尝试实现 merge join。您的排序键看起来不错,但您的数据实际上是排序的吗? Redshift 不会自动保持表的行按排序键排序,redshift 无法在您的表上执行合并连接。在表上运行完全真空,redshift 将开始执行合并连接。

select * from svv_table_info where table = 'impressions'
select * from svv_table_info where table = 'clicks'

使用上述查询检查表中未排序的数据量。 在你的两张桌子上运行完全真空。根据未排序数据的数量,这可能需要一段时间并占用大量集群资源。

VACUUM impressions to 100 percent
VACUUM clicks to 100 percent

如果我做了一个错误的假设,请发表评论,我会重新调整我的答案。

【讨论】:

感谢拉胡尔的回答。将尝试这些建议

以上是关于在 Redshift 中使用连接的最佳方式的主要内容,如果未能解决你的问题,请参考以下文章

将一张表从 RDS / postgres 加载到 Redshift

为 SQL Redshift 连接两个整数的最佳方法是啥?

在没有 AWS Pipeline 的情况下,将数据(csv 文件)从 s3 自动传输到 Redshift 的最佳方式是啥?

Redshift 连接未以正确方式关闭

AWS中ETL流程的最佳方式是啥

如何在 Kafka 中进行转换(PostgreSQL-> Red shift )