Сравнение улья с совокупным результатом подзапроса

У меня есть таблица (например, с именем Источник), например:

-------------
|Name|ID|...|
-------------
|A   |1 |...|
|A   |2 |...|
|A   |3 |...|
|B   |1 |...|
|B   |2 |...|
|C   |1 |...|
-------------

таким образом, каждое Имя может иметь несколько записей, каждая из которых имеет увеличивающийся ID (который, в свою очередь, разделен по Имени, как вы, вероятно, уже поняли) .

Теперь у меня есть другая таблица (называемая Dest), в которую я загружаю таблицу Source, например. ежедневные партии. Однако я хочу загрузить дельту только из Source, поэтому, если моя таблица Dest выглядит так:

-------------
|Name|ID|...|
-------------
|A   |1 |...|
|A   |2 |...|
|B   |1 |...|
-------------

Я только хочу скопировать разницу из Source в Dest , которая будет следующей:

-------------
|Name|ID|...|
-------------
|A   |3 |...|
|B   |2 |...|
|C   |1 |...|
-------------

По другим причинам я не могу использовать для этого отметку времени или минус, поэтому единственный способ найти разницу — получить MAX(ID) для каждого Имени и получить только записи > MAX(ID) для каждого Имени.

Самая быстрая реализация — через подзапрос, который подготавливает все MAX(ID) для каждого Name и использует его для устранения меньших ID. :

SELECT s.* FROM Source s 
LEFT JOIN (
 SELECT d.NAME, MAX(d.ID) AS MAX_ID
 FROM Dest d
 GROUP BY d.NAME) n
ON s.NAME = n.NAME
WHERE s.ID > COALESCE(n.MAX_ID,0)

Однако, поскольку в таблицах много записей, я считаю, что это будет не очень эффективно, если только Hive не оптимизирует его достаточно автоматически, в чем я не уверен.

Я надеялся сделать что-то вроде этого:

SELECT s.* FROM Source s 
WHERE s.ID > (SELECT COALESCE(MAX(d.ID),0)
              FROM Dest d
              WHERE d.NAME = s.NAME)

Таким образом, я бы не вычислял MAX(ID) для всех записей, а вычислял бы его только для текущего Имени. Но это, по-видимому, невозможно в Hive.

Итак, мой вопрос: как лучше всего реализовать обнаружение дельты в Hive?


person Johnny16    schedule 21.06.2017    source источник


Ответы (1)


Почему бы вам просто не использовать left join и where?

SELECT s.*
FROM Source s LEFT JOIN
     Dest d
     ON s.NAME = d.NAME AND s.ID = d.ID
WHERE d.NAME IS NULL;

Если вам действительно нужно сделать это, используя максимальный идентификатор из Dest, то ваш подход с GROUP BY должен подойти в Hive.

person Gordon Linoff    schedule 21.06.2017
comment
Причина в том, что на самом деле таблица Source является своего рода историческим архивом, особенно каждый раз, когда некоторые идентификаторы добавляются к имени, предыдущие идентификаторы также добавляются. Например. вчера были добавлены записи 1, 2 для имени A, сегодня записи 1,2,3 для имени A добавлено, поэтому снова добавляется 1,2, а затем 3. Это затрудняет использование вашего подхода или отметки времени. Будет ли мой подход GROUP BY по-прежнему хорошо работать с миллионами записей, или есть лучший способ, например, какая-то альтернатива второму подходу? - person Johnny16; 21.06.2017
comment
@Джонни16. . . Как вы описали проблему, left join все еще должен работать (даже с дубликатами). Тем не менее, это делает group by более привлекательным. - person Gordon Linoff; 21.06.2017