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

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

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

  1. 行数(1.7 亿)
  2. 分发密钥(ad_campaign)
  3. 排序键(created_on)

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

  1. 行数(8000 万)
  2. 分发密钥(ad_campaign)
  3. 排序键(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 个节点。

标签: amazon-redshift


【解决方案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
    

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

    【讨论】:

    • 感谢拉胡尔的回答。将尝试这些建议
    猜你喜欢
    • 2018-10-31
    • 2018-06-26
    • 1970-01-01
    • 2012-03-24
    • 2015-03-26
    • 2015-12-18
    • 2021-11-20
    • 2021-12-31
    • 1970-01-01
    相关资源
    最近更新 更多