【问题标题】:Redshift EXCEPT much slower than LEFT JOINRedshift EXCEPT 比 LEFT JOIN 慢得多
【发布时间】:2017-12-15 19:38:23
【问题描述】:

我正在尝试将一个临时表(“新数据”)与另一个表(“现有数据”)进行比较,以识别添加/更改/删除的行,并最终确定一个 upsert。这是一项昂贵的操作 - 在大型数据集上进行完全差异。我真的很想使用EXCEPT 命令来提高语法清晰度,但我遇到了严重的性能问题,发现LEFT JOIN 更好。

这两个表具有相似的行数和相同的架构(几乎 - “第二”表有一个额外的 created_date 列)。

他们都共享distkey(date)sortkey(date, id1, id2);我什至在EXCEPT 语句中以“正确”顺序指定列以帮助优化器。

下面是针对每个测试大小的数据子集的查询计划。

explain
select date, id1, id2, id3, value, attr1, attr2, attr3 from new_data
except select date, id1, id2, id3, value, attr1, attr2, attr3 from existing_data;

XN SetOp Except  (cost=1000002817944.78..1000003266822.61 rows=1995013 width=1637)
  ->  XN Sort  (cost=1000002817944.78..1000002867820.09 rows=19950126 width=1637)
        Sort Key: date, id1, id2, id3, value, attr1, attr2, attr3
        ->  XN Append  (cost=0.00..399002.52 rows=19950126 width=1637)
              ->  XN Subquery Scan "*SELECT* 1"  (cost=0.00..199501.26 rows=9975063 width=1637)
                    ->  XN Seq Scan on new_data  (cost=0.00..99750.63 rows=9975063 width=1637)
              ->  XN Subquery Scan "*SELECT* 2"  (cost=0.00..199501.26 rows=9975063 width=1636)
                    ->  XN Seq Scan on existing_data  (cost=0.00..99750.63 rows=9975063 width=1636)

和我丑得多的LEFT JOIN比较

explain
select t1.* from new_data t1 
left outer join existing_data t2 on     
    t1.date = t2.date
    and t1.id1 = t2.id1
    and coalesce(t1.id2, -1) = coalesce(t2.id2, -1)
    and coalesce(t1.id3, -1) = coalesce(t2.id3, -1)
    and coalesce(t1.value, -1) = coalesce(t2.value, -1) 
    and coalesce(t1.attr1, '') = coalesce(t2.attr1, '')
    and coalesce(t1.attr2, '') = coalesce(t2.attr2, '')
    and coalesce(t1.attr3, '') = coalesce(t2.attr3, '')
where t2.id1 is null;

XN Merge Left Join DS_DIST_NONE  (cost=0.00..68706795.68 rows=9975063 width=1637)
  Merge Cond: (("outer".date = "inner".date) AND (("outer".id1)::bigint = "inner".id1))
  Join Filter: (((COALESCE("outer".id2, -1))::bigint = COALESCE("inner".id2, -1::bigint)) AND ((COALESCE("outer".id3, -1))::bigint = COALESCE("inner".id3, -1::bigint)) AND ((COALESCE("outer".value, -1::numeric))::double precision = COALESCE("inner".value, -1::double precision)) AND ((COALESCE("outer".attr1, ''::character varying))::text = (COALESCE("inner".attr1, ''::character varying))::text) AND ((COALESCE("outer".attr2, ''::character varying))::text = (COALESCE("inner".attr2, ''::character varying))::text) AND ((COALESCE("outer".attr3, ''::character varying))::text = (COALESCE("inner".attr3, ''::character varying))::text))
  Filter: ("inner".id1 IS NULL)
  ->  XN Seq Scan on new_data t1  (cost=0.00..99750.63 rows=9975063 width=1637)
  ->  XN Seq Scan on existing_data t2  (cost=0.00..99750.63 rows=9975063 width=1636)

查询成本为1000003266822.6168706795.68。我知道我不应该在查询之间进行比较,但它在执行时间中得到了证明。知道为什么EXCEPT 语句比LEFT JOIN 慢得多吗?

【问题讨论】:

    标签: performance left-join amazon-redshift database-performance sql-except


    【解决方案1】:

    left join 正在为每个(可能是有序的)键值生成一堆交叉连接的行,然后通过on 过滤掉它不想要的行;当(可能是有序的)旧键值超过新键值时,它也可以停止,因为不再有匹配项——这也涉及通过一些coalesce SARG 智能进行一些推断。 except 首先对所有内容进行排序。在这种情况下,排序成本超过生成和丢弃行,乘以遍历右侧表的每个键的行。当然,优化器可以在其except 规划中包含outer join 惯用语——但显然没有。

    相关:PostgreSQL: NOT IN versus EXCEPT performance difference

    【讨论】:

      猜你喜欢
      • 2019-10-09
      • 2013-02-07
      • 2015-03-03
      • 1970-01-01
      • 1970-01-01
      • 2019-04-22
      • 2021-03-22
      • 2023-03-24
      • 2018-07-10
      相关资源
      最近更新 更多