如果数据集很大,有什么技巧可以避免或减少一对多联接和非等联接的成本?

时间:2019-01-09 00:04:11

标签: sql database postgresql apache-spark pyspark

我想知道人们在拥有大量数据时如何应对大型的一对多联接,尤其是非股权联接。如果两个表AB的键是足够重复的,则两个表之间的联接输出可以接近| A |的大小。 * | B |。大型公司的分析中必须经常提到这一点,所以我想知道有什么方法可以减少这些联接的计算时间。

但是,AB很多时候是不同的表,在这种情况下,我认为不能使用LAG()

非等额一对多联接的示例

作为可能需要非等号和一对多联接的情况的简化示例,我有表AB,每个表都有数字{{1} }列,日期字段id和某些字段date_created。对于表group中的每一行,我想要A的{​​{1}}列以及表id中相应行的所有数据,其中A是最大的值,例如B> B.date_createdA.date_created。换句话说,我想要表B.date_created的最新行相对于列A.group = B.group中每一行的Bdate_created字段。

使用窗口功能时的代码

在大多数出现这些非等额联接的情况下,groupA是同一表,而A字段实际上对应于同一列。在这种情况下,我可以使用B窗口函数:

date_created

我相信它比自我加入更为有效。但是,当要比较的列不同或属于不同的表时,这种方法是不可能的。

窗口功能不可行时的代码

我使用以下代码为表LAG()中的每一行计算表WITH id_tuples AS ( SELECT A.id, LAG(A.id, 1) OVER (PARTITION BY A.group ORDER BY A.date_created) AS lagged_id FROM A ) SELECT id_t.id, A.* FROM id_tuples id_t INNER JOIN A ON A.id = id_t.lagged_id 的最新行。

B

这里的问题是分组变量ASELECT * FROM ( SELECT A.id, B.*, DENSE_RANK() OVER (PARTITION BY A.id ORDER BY B.date_created) AS date_rank FROM A INNER JOIN B ON B.group = A.group AND B.date_created < A.date_created ) WHERE date_rank = 1 只能具有几个不同的值。然后,该联接几乎变成了笛卡尔联接,并且子查询中输出结果的数量可能比A和B的行之和大许多数量级。这很浪费,因为外部查询会丢弃大部分的通过过滤A.group获得结果。

是否存在更好的结构化查询结构,以减少这些连接的成本,或者在这些情况下完全避免使用它们?我在摘要中询问,但是我发现我的关系数据库和Spark集群(一旦我将数据移到那里)都没有足够的内存来处理这种联接。即使在较小的数据集上,此操作也需要大量时间才能运行。而且我不认为我的数据集相对于其他人正在做的事情特别大。

1 个答案:

答案 0 :(得分:0)

您的第一个查询可以简单地写为:

SELECT A.id,
       LAG(A.id, 1) OVER (PARTITION BY A.group ORDER BY A.date_created) AS lagged_id
FROM A;

不需要JOIN

对于第二个查询,一种方法是横向联接:

SELECT A.id, B.*,
FROM A LEFT JOIN LATERAL
     (SELECT B.*
      FROM B
      WHERE B.group = A.group AND
            B.date_created < A.date_created
      ORDER BY B.date_created DESC
      FETCH FIRST 1 ROW ONLY
     ) B;

这应该在B(GROUP, date_created)上使用索引。