Лучший способ получить 1-ю запись на раздел: FIRST_VALUE vs ROW_NUMBER

#sql #amazon-redshift

#sql #amazon-redshift

Вопрос:

Я ищу самый быстрый способ получить 1-ю запись (столбцы a, b, c) для каждого раздела (a, b) с использованием SQL. Таблица состоит из ~ 10 000 000 строк.

Подход # 1:

 SELECT * FROM (
    SELECT a,b,c, 
    ROW_NUMBER() OVER ( PARTITION by a, b ORDER BY date DESC) as row_num
    FROM T 
) WHERE row_num =1
  

Но это, вероятно, выполняет дополнительную работу за сценой — мне нужна только 1-я строка для каждого раздела.

Подход № 2 с использованием FIRST_VALUE(). Поскольку FIRST_VALUE() возвращает выражение, позвольте упаковать / объединить a, b, c, используя некоторый разделитель, в одно выражение, например:

 SELECT FIRST_VALUE(a ',' 'b' ',' c) 
OVER ( PARTITION by a, b ORDER BY date  DESC rows unbounded preceding) FROM T
  

Но в этом случае мне нужно распаковать результат, что является дополнительным шагом.

Подход № 3 с использованием FIRST_VALUE() — повторите (…) для a , b :

 SELECT 
FIRST_VALUE(a) 
OVER ( PARTITION by a, b ORDER BY date  DESC rows unbounded preceding),
FIRST_VALUE(b) 
OVER ( PARTITION by a, b ORDER BY date  DESC rows unbounded preceding),
c 
FROM T
  

В подходе № 3 я не знаю, достаточно ли умен database engine (Redshift) для разделения только один раз

Комментарии:

1. вы действительно пробовали запускать их? У нас не очень жесткие требования к производительности, и мы часто используем подход № 3 даже с 10 столбцами событий, использующими одно и то же окно. Я всегда был убежден, что механизм запросов достаточно умен, чтобы заметить одно и то же определение окна и способен повторно использовать (хотя доказательств нет). Также то, что мы обычно делаем, это SELECT DISTINCT window functions over columns — в противном случае вы получаете тонны дубликатов

2. Вы пробовали сравнивать запросы? Мне любопытно, каковы последствия каждого решения для производительности.

3. » Мне нужна только 1-я строка для каждого раздела » вы, кажется, ожидаете здесь какой-то возможности быстрого доступа к базе данных. Это не так. Для надежного поиска «первой строки» у базы данных нет альтернативы сортировке всех строк в разделе, она не может использовать короткий путь. Если вы хотите знать, какой вариант является самым быстрым, проверьте план выполнения. Кстати: другим вариантом было бы использовать объединение с производной таблицей: pastebin.com/z7CV7FKD

Ответ №1:

Первый запрос отличается от двух других. Первый возвращает только одну строку для каждой группы. Два других возвращают те же строки, что и в исходном запросе.

Вы должны использовать версию, которая делает то, что вы хотите, которая, я полагаю, является первой. Если вы добавите select distinct or group by к другим запросам, это, вероятно, добавит накладные расходы, которые сделают их медленнее — но вы можете проверить свои данные, чтобы убедиться, что это правда.

Ваша интуиция верна, что первый запрос выполняет ненужную работу. В базах данных, которые полностью поддерживают индексы, коррелированный подзапрос часто выполняется быстрее. Однако я не думаю, что это имело бы место в Redshift.