Как явные разделы таблиц в Databricks влияют на производительность записи?
У нас есть следующий сценарий:
- У нас есть существующая таблица, содержащая ок. 15 миллиардов записей. Это не было явно разделено на создание.
- Мы создаем копию этой таблицы с разделами, надеясь на более быстрое время чтения для определенных типов запросов.
- Наши таблицы находятся в облаке Databricks Cloud, и мы используем Databricks Delta.
- Мы обычно фильтруем по двум столбцам, один из которых является идентификатором сущности (350 000 различных значений), а другой - датой, когда произошло событие (на данный момент 31 отдельное значение, но увеличивается каждый день!).
Итак, создавая нашу новую таблицу, мы запустили такой запрос:
CREATE TABLE the_new_table
USING DELTA
PARTITIONED BY (entity_id, date)
AS SELECT
entity_id,
another_id,
from_unixtime(timestamp) AS timestamp,
CAST(from_unixtime(timestamp) AS DATE) AS date
FROM the_old_table
Этот запрос выполняется в течение 48 часов и считается. Мы знаем, что это делает успехи, потому что мы нашли около 250 тыс. Префиксов, соответствующих первому ключу раздела в соответствующем префиксе S3, и в префиксах, конечно, есть несколько больших файлов.
Тем не менее, у нас возникают некоторые трудности с отслеживанием того, сколько прогресса было достигнуто, и сколько еще времени мы ожидаем, что это займет.
Пока мы ждали, мы опробовали такой запрос:
CREATE TABLE a_test_table (
entity_id STRING,
another_id STRING,
timestamp TIMESTAMP,
date DATE
)
USING DELTA
PARTITIONED BY (date);
INSERT INTO a_test_table
SELECT
entity_id,
another_id,
from_unixtime(timestamp) AS timestamp,
CAST(from_unixtime(timestamp) AS DATE) AS date
FROM the_old_table
WHERE CAST(from_unixtime(timestamp) AS DATE) = '2018-12-01'
Обратите внимание, что основное отличие в схеме новой таблицы заключается в том, что мы разбили раздел только на дату, а не на идентификатор объекта. Выбранная нами дата содержит почти ровно четыре процента данных старой таблицы, на которые я хочу указать, потому что она намного больше 1/31. Конечно, поскольку мы выбираем по единственному значению, которое оказывается тем же самым, на которое мы разбили раздел, мы фактически пишем только один раздел, по сравнению с, вероятно, сотнями тысяч или около того.
Создание этой тестовой таблицы заняло 16 минут с использованием того же числа рабочих узлов, поэтому мы ожидаем (исходя из этого), что создание таблицы в 25 раз больше займет всего около 7 часов.
Этот ответ частично подтверждает, что использование слишком большого количества разделов может вызвать проблему, но основные причины, по-видимому, сильно изменились за последние пару лет, поэтому мы стремимся понять, какими могут быть текущие проблемы; документы Databricks не были особенно осветительными.
На основании опубликованных рекомендаций по частоте запросов для S3 кажется, что увеличение количества разделов (ключевых префиксов) должно повысить производительность. Пагубные разделы кажутся нелогичными.
В итоге: мы ожидаем записать тысячи записей в каждый из тысяч разделов. Похоже, что сокращение количества разделов значительно сокращает время, необходимое для записи данных таблицы. Почему это так? Существуют ли общие рекомендации по количеству разделов, которые должны быть созданы для данных определенного размера?
2 ответа
Я вообще не эксперт по данным, но надеюсь, что эти пули помогут
Количество перегородок
Количество созданных разделов и файлов будет влиять на производительность вашей работы, не смотря ни на что, особенно если использовать s3 в качестве хранилища данных, однако это количество файлов должно легко обрабатываться кластером размера спуска
Динамический раздел
Существует огромная разница между разделами динамически с помощью двух ключей вместо одного, позвольте мне подробнее остановиться на этом.
Когда вы разбиваете данные динамически, в зависимости от количества задач и размера данных, для каждого раздела может быть создано большое количество небольших файлов, что может (и, вероятно, повлияет) на производительность следующих заданий, которые потребуют использования этих данных. особенно если ваши данные хранятся в ORC, паркетном или любом другом столбцовом формате. Обратите внимание, что для этого потребуется только работа только с картой.
Проблема, описанная выше, решается по-разному, и является наиболее распространенной при консолидации файлов. Для этого данные перераспределяются с целью создания больших файлов. В результате потребуется перетасовка данных.
Ваши запросы
Для вашего первого запроса количество разделов будет 350k*31 (около 11 ММ!), Что очень много, учитывая количество перетасовок и задач, необходимых для выполнения задания.
Для вашего второго запроса (который занимает всего 16 минут) количество требуемых задач и требуемых перетасовок намного меньше.
Количество разделов (тасование / сортировка / планирование задач / и т. Д.) И время выполнения вашей работы не имеют линейной регрессии, поэтому математика складывается в этом случае.
Рекомендации для
Я думаю, что вы уже получили его, вы должны разделить свою работу etl на 31 один запрос, что позволит оптимизировать время выполнения
Вы должны разделить ваши данные по date
потому что кажется, что вы постоянно добавляете данные с течением времени в хронологическом порядке. Это общепринятый подход к разделению данных временных рядов. Это означает, что вы будете писать в один раздел даты каждый день, а ваши предыдущие разделы даты больше не обновляются (это хорошо).
Конечно, вы можете использовать вторичный ключ раздела, если ваш сценарий использования выигрывает от него (т.е. PARTITIONED BY (date, entity_id)
)
Разделение по дате потребует, чтобы ваше чтение этих данных всегда было выполнено также по дате, чтобы добиться максимальной производительности. Если это не ваш вариант использования, вам придется уточнить свой вопрос.
Сколько разделов?
Никто не может дать вам ответ о том, сколько разделов вы должны использовать, потому что каждый набор данных (и кластер обработки) отличается. Чего вы хотите избежать, так это "искажения данных", когда одному работнику приходится обрабатывать огромные объемы данных, в то время как другие не работают. В вашем случае это произойдет, если один clientid
например, 20% вашего набора данных. Разделение по дате должно предполагать, что каждый день содержит примерно одинаковый объем данных, поэтому каждый работник одинаково занят.
Я не знаю конкретно о том, как Databricks записывает на диск, но в Hadoop я хотел бы, чтобы каждый рабочий узел записывал свою собственную файловую часть, и, следовательно, ваша производительность записи параллельна на этом уровне.
Мои рекомендации в случае использования секционированных столбцов:
- Определите количество всех столбцов и выберите те, которые имеют конечное количество времени, поэтому исключите идентификаторы и столбцы даты.
- Определите основной поиск по таблице, возможно, это дата или какое-то категориальное поле
- Сгенерируйте подстолбцы с конечным числом элементов, чтобы ускорить пример поиска, в случае дат можно разложить его на год, месяц, день и т. Д., Или в случае целочисленных идентификаторов, разложить их на целочисленное деление из этих идентификаторов% [1,2,3 ...]
Как я упоминал ранее, использование столбцов с высокой мощностью для разделения приведет к снижению производительности из-за создания большого количества файлов, что является наихудшим рабочим случаем.
Желательно работать с файлами, размер которых не превышает 1 Гб, для этого при создании дельта-таблицы рекомендуется занимать "coalesce (1)"
Если вам нужно выполнить обновления или вставки, укажите наибольшее количество секционированных столбцов, чтобы исключить случайные случаи чтения файла, что очень эффективно для сокращения времени.