Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Помимо сложности семантической модели и сложности запросов, производительность Direct Lake зависит от хорошо настроенных таблиц Delta для эффективной и быстрой загрузки столбцов (транскодирования) и оптимального выполнения запросов. Убедитесь, что вы применяете оптимизацию V-Order. Кроме того, сохраняйте количество файлов Parquet небольшими, используйте большие группы строк и старайтесь свести к минимуму влияние обновлений данных в журнале Delta. Это распространенные рекомендации, которые помогут обеспечить быстрое выполнение запросов в холодном, полутеплом, теплом и горячем состояниях режима Direct Lake.
В этой статье объясняется, как производительность Direct Lake зависит от работоспособности таблиц Delta и эффективных обновлений данных. Понимание этих зависимостей имеет решающее значение. Вы узнаете, что макет данных в файлах Parquet настолько же важен для производительности запросов, как и хорошо спроектированная семантическая модель и оптимизированные меры анализа данных (DAX).
Что нужно знать
В этой статье предполагается, что вы уже знакомы со следующими понятиями:
- Таблицы Delta в OneLake: подробная информация о таблицах Delta в OneLake доступна в документации по основам Microsoft Fabric.
- Файлы Parquet, группы строк и журнал Delta: формат файла Parquet, включая порядок организации данных в группы строк и блоки столбцов и способ обработки метаданных, объясняется в документации по формату файла Parquet. См. также документацию по протоколу журнала транзакций Delta.
- Оптимизация таблиц Delta и V-Order: см. документацию по Fabric Lakehouse о поддержке таблиц Delta, например оптимизация таблиц Delta Lake и V-Order.
- Фреймирование и перекодирование. Обновление семантической модели Direct Lake (кадрирование) и загрузка данных столбцов по запросу (транскодирование) являются важными понятиями, описанными на вводном уровне в статье обзора Direct Lake.
- Формула и подсистема хранилища. При выполнении запроса DAX подсистема формул создает план запроса и извлекает необходимые данные и начальные агрегаты из подсистемы хранилища. Оптимизации, рассмотренные в этой статье, сосредоточены на подсистеме хранилища. Дополнительные сведения о подсистеме формул и подсистеме хранилища см. в документации разработчика служб Analysis Services.
- VertiPaq и VertiScan: в режиме импорта и в режиме Direct Lake подсистема хранилища использует свой движок VertiPaq для поддержания столбчатого хранилища в памяти. VertiScan позволяет обработчику формул взаимодействовать с VertiPaq. Дополнительные сведения см. в документации разработчика служб Analysis Services.
- Кодировка словаря: файлы Parquet и VertiPaq используют кодировку словаря, которая является методом сжатия данных, применяемым к отдельным столбцам различных типов данных, таких как int, long, date и char. Он работает путем хранения каждого уникального значения столбца в памяти в виде целого числа с помощью кодирования длины выполнения (RLE)/Bit-Packing гибридной кодировки. VertiPaq всегда использует кодировку словаря, но Parquet может переключиться на простую кодировку или дельта-кодировку при определённых обстоятельствах, как объясняется в кодировках в документации Parquet File-Format, что требует повторного кодирования данных с соответствующим эффектом на производительность транскодирования.
- Фрагменты столбцов и сегменты столбцов: Относятся к способу, которым данные столбцов хранятся в форматах Parquet и VertiPaq для эффективного извлечения данных. Каждый столбец в таблице делится на небольшие блоки, которые можно обрабатывать и сжимать независимо. VertiPaq называет эти фрагменты сегментами. Для получения сведений о сегментах столбцов в семантической модели Direct Lake можно использовать набор строк схемы DISCOVER_STORAGE_TABLE_COLUMN_SEGMENTS .
- Записные книжки Python и Jupyter Notebook: Jupyter Notebook предоставляет интерактивную среду для записи и запуска кода Python. Базовые знания о Python полезны, если вы хотите следовать фрагментам кода далее в этой главе. Дополнительные сведения см. в справочнике по языку Python. Сведения об использовании записных книжек в Microsoft Fabric см. в статье "Использование записных книжек " Microsoft Fabric".
Что влияет на производительность запросов Direct Lake
В этом разделе приведены основные факторы, влияющие на производительность Direct Lake. В последующих разделах приведены более подробные объяснения:
- Сжатие V-Order: эффективность сжатия может повлиять на производительность запросов, так как лучшее сжатие приводит к более быстрой загрузке данных и более эффективной обработке запросов. Загрузка данных выполняется быстро, так как потоковая передача сжатых данных повышает эффективность транскодирования. Производительность запросов также оптимальна, так как сжатие V-Order позволяет VertiScan вычислить результаты непосредственно поверх сжатых данных, пропуская шаг распаковки.
- Типы данных. Использование соответствующих типов данных для столбцов может улучшить сжатие и производительность. Например, используйте целые типы данных вместо строк, где это возможно, и избегайте хранения целых чисел в виде строк.
- Размер и количество сегментов: VertiPaq сохраняет данные столбцов в сегментах. Большое количество небольших сегментов может отрицательно повлиять на производительность запросов. Для больших таблиц Direct Lake предпочитает большие размеры сегментов, например от 1 до 16 миллионов строк.
- Кратность столбцов: столбцы высокой кратности (столбцы со многими уникальными значениями) могут замедлить производительность. Сокращение кардинальности, где это возможно, может помочь.
- Индексы и агрегаты: столбцы с более низким кратностью пользуются кодировкой словаря, что может ускорить запросы, уменьшая объем данных, которые необходимо сканировать.
- Резервная версия DirectQuery: резервные операции могут привести к более медленной производительности запросов, так как данные теперь должны быть получены из конечной точки аналитики SQL источника данных Fabric. Кроме того, резервный вариант использует планы гибридных запросов для поддержки DirectQuery и VertiScan с некоторыми компромиссами по производительности, даже если Direct Lake не требует резервного восстановления. По возможности отключите резервный режим DirectQuery, чтобы избежать гибридных планов запросов.
-
Степень расположения в памяти: семантические модели Direct Lake могут находиться в холодном, полутеплом, теплом или горячем состоянии с улучшением производительности от холодного до горячего. Переход быстро от холодного к теплому является ключом к хорошей производительности Direct Lake.
- Холодный: магазин VertiPaq пуст. Все данные, необходимые для ответа на запрос DAX, должны быть загружены из таблиц Delta.
- Semiwarm: Direct Lake исключает те сегменты столбцов во время обрамления, которые принадлежат удаленным группам строк. Это означает, что необходимо загрузить только обновленные или недавно добавленные данные. Семантическая модель Direct Lake также может перейти в полугорячее состояние при перегрузке памяти, когда необходимо выгрузить сегменты и объединить индексы из-за давления на память.
- Тепло: данные столбца, необходимые для ответа на запрос DAX, уже полностью загружены в память.
- Горячее: данные столбца уже полностью загружены в память, кэши VertiScan заполняются, а запросы DAX попадают в кэши.
- Давление на память: Direct Lake должен загружать все данные столбцов, необходимые для ответа на запрос DAX в память, что может исчерпать доступные ресурсы памяти. При недостатке памяти Direct Lake должен выгрузить ранее загруженные данные столбца, которые он может загрузить заново для последующих запросов DAX. Адекватное изменение размера семантических моделей Direct Lake может помочь избежать частой перезагрузки.
Производительность размещения памяти и запросов
Direct Lake лучше всего работает в теплом или горячем состоянии, в то время как холодные состояния приводят к замедлению производительности. Direct Lake избегает возврата к холодному как можно больше, используя добавочное обрамление.
Начальная загрузка
После начальной загрузки семантической модели данные столбцов пока не будут находиться в памяти. Прямое озеро холодно. Когда клиент отправляет запрос DAX в семантическую модель Direct Lake, находящуюся в холодном состоянии, Direct Lake должен выполнить следующие основные задачи, чтобы запрос DAX мог быть обработан и на него получен ответ:
Перекодирование словаря VertiPaq. Direct Lake должен объединить локальные словари Parquet для каждого блока столбца, чтобы создать глобальный словарь VertiPaq для столбца. Эта операция слияния влияет на время отклика запроса.
Загрузка блоков столбцов Parquet в сегменты столбцов. В большинстве случаев это прямое перенаправка идентификаторов данных Parquet на идентификаторы VertiPaq, когда обе стороны могут использовать RLE/Bit-Packing гибридную кодировку. Если словари Parquet используют простую кодировку, VertiPaq должен преобразовать значения в RLE/Bit-Packing гибридную кодировку, которая занимает больше времени.
- Производительность Direct Lake оптимальна для V-Ordered файлов Parquet, так как V-Ordering улучшает качество сжатия RLE. Direct Lake может загружать плотные V-упорядоченные данные быстрее, чем менее сжатые данные.
Создание индексов соединений. Если запрос DAX обращается к столбцам из нескольких таблиц, Direct Lake должен создавать индексы соединения в соответствии с связями таблиц, чтобы VertiScan мог правильно соединить таблицы. Чтобы создать индексы соединения, Direct Lake должен загрузить словари ключевых столбцов, участвующих в связи, и сегменты столбцов первичного ключевого столбца (столбец на одной стороне связи таблицы).
Применение дельта-векторов удаления. Если исходная таблица Delta использует векторы удаления, Direct Lake должна загрузить эти векторы удаления, чтобы гарантировать, что удаленные данные исключены из обработки запросов.
Заметка
Холодное состояние также можно вызвать, отправив команду XMLA
processClear
, за которой следуетprocessFull
, в модель. КомандаProcessClear
удаляет все данные и ассоциацию с указанной версией таблицы Delta. КомандаProcessFull
XMLA выполняет фрейминг, чтобы привязать модель к последней доступной версии коммита Delta.
Добавочное обрамление
Во время создания структуры Direct Lake анализирует журнал Delta каждой таблицы Delta и удаляет загруженные сегменты столбцов и индексы соединения только при изменении исходных данных. Словари сохраняются, чтобы избежать ненужных перекодирования, а новые значения просто добавляются в существующие словари. Этот инкрементальный подход к обрамлению снижает нагрузку на перезагрузку и улучшает производительность при выполнении холодных запросов.
Вы можете анализировать добавочную эффективность обрамления с помощью INFO.STORAGETABLECOLUMNSEGMENTS()
функции DAX, которая упаковывает DISCOVER_STORAGE_TABLE_COLUMN_SEGMENTS
набор строк схемы. Выполните следующие действия, чтобы обеспечить значимые результаты:
- Запросите семантическую модель Direct Lake, чтобы убедиться, что она находится в активном или разогретом состоянии.
- Обновите таблицу Delta, которую вы хотите исследовать, и обновите семантическую модель Direct Lake, чтобы выполнить фреймирование.
- Запустите запрос DAX, чтобы получить сведения о сегменте столбца с помощью
INFO.STORAGETABLECOLUMNSEGMENTS()
функции, как показано на следующем снимке экрана. На снимке экрана для иллюстрации используется небольшая примерная таблица. Каждый столбец имеет только один сегмент. Сегменты не загружены в оперативную память. Это означает истинное холодное состояние. Если модель была теплой перед обрамлением, это означает, что таблица Delta была обновлена с помощью шаблона разрушительной загрузки данных, что делает невозможным использовать добавочное обрамление. Шаблоны обновления таблицы Delta размещены далее в этой статье.
Заметка
Если разностная таблица не получает обновлений, перезагрузка не требуется для столбцов, уже находящихся в памяти. При использовании недеструктивных шаблонов обновления запросы показывают гораздо меньший эффект производительности после обрамления, так как добавочное обрамление по сути позволяет Direct Lake обновлять значительные части существующих данных в памяти.
Полная загрузка в память
Благодаря словарям, сегментам столбцов и индексам соединений, Direct Lake достигает теплого состояния с производительностью запросов, сопоставимой с режимом импорта. В обоих режимах число и размер сегментов столбцов играют важную роль в оптимизации производительности запросов.
Различия в разностных таблицах
Файлы Parquet упорядочивают данные по столбцам, а не строкам. Direct Lake также упорядочивает данные по столбцам. Выравнивание облегчает бесшовную интеграцию, но существуют важные различия, в частности, касающиеся групп строк и словарей.
Группы строк и сегменты столбцов
Группа строк в файле Parquet состоит из блоков столбцов, и каждый фрагмент содержит данные для определенного столбца. С другой стороны, сегмент столбца в семантической модели также содержит фрагмент данных столбца.
Существует прямая связь между общим числом групп строк таблицы Delta и числом сегментов для каждого столбца соответствующей таблицы семантической модели. Например, если таблица Delta во всех текущих файлах Parquet содержит три группы строк в общей сложности, соответствующая таблица семантической модели содержит три сегмента на столбец, как показано на следующей схеме. Другими словами, если таблица Delta имеет большое количество крошечных групп строк, соответствующая семантическая таблица модели также будет иметь большое количество крошечных сегментов столбцов. Это отрицательно влияет на производительность запросов.
Заметка
Так как Direct Lake предпочитает большие сегменты столбцов, группы строк исходных разностных таблиц должны быть в идеале большими.
Локальные словари и глобальный словарь
Общее число групп строк таблицы Delta также оказывает непосредственное влияние на производительность перекодирования словарей, так как файлы Parquet используют локальные словари, а семантические модели Direct Lake используют глобальный словарь для каждого столбца, как показано на следующей схеме. Чем выше число групп строк, тем выше число локальных словарей, которые Direct Lake должен объединить для создания глобального словаря, и чем дольше требуется для завершения перекодирования.
Шаблоны обновления таблицы Delta
Метод, используемый для приема данных в таблицу Delta, может значительно влиять на эффективность построения инкрементальных фреймов. Например, использование параметра Overwrite при загрузке данных в существующую таблицу стирает журнал Delta с каждой загрузкой. Это означает, что Direct Lake не может использовать инкрементальное формирование кадров и должен заново загрузить все данные, словари и индексы соединений. Такие разрушительные шаблоны обновлений отрицательно влияют на производительность запросов.
В этом разделе рассматриваются шаблоны обновления таблицы Delta, позволяющие Direct Lake использовать добавочное обрамление, сохраняя элементы хранилища столбцов VertiPaq, такие как словари, сегменты столбцов и индексы соединения, чтобы повысить эффективность транскодирования и повысить производительность холодных запросов.
Пакетная обработка без секционирования
Этот шаблон обновления собирает и обрабатывает данные в больших пакетах с запланированными интервалами, например еженедельно или ежемесячно. По мере поступления новых данных старые данные часто удаляются в скользящем окне, чтобы сохранить размер таблицы под контролем. Однако удаление старых данных может быть проблемой, если данные распределены по большинству файлов Parquet. Например, удаление одного дня из тридцатидневного периода может затронуть 95% файлов Parquet вместо 5%. В этом случае Direct Lake придется перезагрузить 95% данных даже для относительно небольшой операции удаления. Эта проблема также относится к обновлениям существующих строк, так как обновления представляют собой комбинацию операций удаления и добавления. Вы можете проанализировать эффект операций удаления и обновления с помощью Delta Analyzer, как описано далее в этой статье.
Пакетная обработка с секционированием
Секционирование таблиц Delta может помочь уменьшить эффект операций удаления, поскольку таблица разделяется на небольшие файлы формата Parquet, хранящиеся в папках, основанных на уникальных значениях в столбце секционирования. Часто используемые столбцы секционирования включают дату, регион или другие категории измерений. В предыдущем примере удаления одного дня из 30-дневного периода таблица Delta, разделённая по дате, ограничивает удаление только файлами Parquet, относящимися к секции этого дня. Однако важно отметить, что обширное секционирование может привести к значительному увеличению количества файлов Parquet и групп строк, что приводит к чрезмерному увеличению сегментов столбцов в семантической модели Direct Lake, отрицательно влияя на производительность запросов. Выбор столбца раздела с низкой кардинальностью имеет решающее значение для производительности запросов. В качестве рекомендации столбец должен иметь менее 100-200 различных значений.
Добавочная загрузка
При добавочной загрузке процесс обновления вставляет новые данные только в таблицу Delta, не затрагивая существующие файлы Parquet и группы строк. Нет никаких удалений. Direct Lake может загружать новые данные постепенно без необходимости удалять и перезагружать существующие элементы хранилища столбцов VertiPaq. Этот метод хорошо работает с добавочным обрамлением Direct Lake. Секционирование Delta-таблицы не требуется.
Потоковая обработка
Обработка данных почти в режиме реального времени может привести к распространению небольших файлов Parquet и групп строк, которые могут негативно повлиять на производительность Direct Lake. Как и в случае с шаблоном добавочной загрузки, не требуется секционировать таблицу Delta. Однако частое обслуживание таблиц является важным для обеспечения того, чтобы количество файлов Parquet и групп строк оставалось в пределах ограничений, указанных в статье обзора Direct Lake. Иными словами, не забывайте регулярно запускать Spark Optimize, например ежедневно или даже чаще. Оптимизация Spark рассматривается снова в следующем разделе.
Заметка
Актуальный анализ в режиме реального времени лучше всего реализуется с использованием Eventstreams, баз данных KQL и Eventhouse. Дополнительные сведения см. в документации по аналитикеReal-Time в Microsoft Fabric .
Обслуживание таблиц Delta
Ключевые задачи обслуживания включают очистку и оптимизацию таблиц Delta. Для автоматизации операций обслуживания можно использовать API Lakehouse, как описано в документации по управлению Lakehouse с помощью REST API Microsoft Fabric .
Пылесосить
Операция вакуумирования удаляет файлы Parquet, которые больше не включены в текущую версию коммита Delta и старше установленного порога хранения. Удаление этих файлов Parquet не влияет на производительность Direct Lake, поскольку Direct Lake загружает только те файлы Parquet, которые находятся в текущем коммите. При ежедневном запуске VACUUM со значениями по умолчанию сохраняются версии фиксации Delta за последние семь дней для путешествия во времени.
Важный
Так как семантическая модель Direct Lake ссылается на конкретную коммит-версию Delta, необходимо убедиться, что таблица Delta сохраняет эту версию, пока вы не обновите модель снова, чтобы переместить её на текущую версию. В противном случае пользователи сталкиваются с ошибками запроса, когда семантическая модель Direct Lake пытается получить доступ к файлам Parquet, которые больше не существуют.
Оптимизация Spark
Оптимизация разностной таблицы объединяет несколько небольших файлов Parquet в меньшее количество больших файлов. Так как это может повлиять на производительность cold Direct Lake, рекомендуется проводить оптимизацию нечасто, например, в выходные или в конце месяца. Оптимизируйте чаще, если небольшие файлы Parquet накапливаются быстро (высокочастотные небольшие обновления), чтобы гарантировать, что таблица Delta остается в пределах пределов защиты.
Секционирование может помочь свести к минимуму влияние оптимизации на добавочное обрамление, так как секционирование эффективно сопоставляет данные. Например, разбиение большой таблицы Delta на основе столбца date_key с низкой кардинальностью ограничит техническое обслуживание максимум семью секциями в неделю. Таблица Delta сохранит большую часть существующих файлов Parquet. Direct Lake придется перезагрузить только семь дней данных.
Анализ обновлений Delta-таблицы
Используйте Delta Analyzer или аналогичные средства для изучения того, как обновления таблицы Delta влияют на файлы Parquet и группы строк. Delta Analyzer позволяет отслеживать эволюцию файлов Parquet, групп строк, блоков столбцов и столбцов в ответ на операции добавления, обновления и удаления . Delta Analyzer доступен как автономный Jupyter Notebook. Он также доступен в библиотеке semantic-link-labs. В следующих разделах используются Semantic Link Labs. Эта библиотека легко установить в записную книжку с помощью %pip install semantic-link-labs
команды.
Размер группы строк
Идеальный размер группы строк для семантических моделей Direct Lake составляет от 1 до 16 миллионов строк, но Структура может использовать более крупные размеры групп строк для больших таблиц, если данные сжимаются. Как правило, мы не рекомендуем изменять размер группы строк по умолчанию. Лучше всего позволить Fabric управлять макетом таблицы Delta. Но это также хорошая идея, чтобы дважды проверить.
Следующий код на Python может являться начальной точкой для анализа размеров групп строк и других характеристик таблицы Delta в lakehouse, подключенном к записной книжке Fabric. В следующей таблице показаны выходные данные для примера таблицы с 1 миллиардами строк.
import sempy_labs as labs
from IPython.display import HTML
from IPython.display import clear_output
table_name = "<Provide your table name>"
# Load the Delta table and run Delta Analyzer
df = spark.read.format("delta").load(f"Tables/{table_name}")
da_results = labs.delta_analyzer(table_name)
# Display the table summary in an HTML table.
clear_output()
df1 = da_results['Summary'].iloc[0]
html_table = "<table border='1'><tr><th>Column Name</th><th>{table_name}</th></tr>"
for column in da_results['Summary'].columns:
html_table += f"<tr><td>{column}</td><td>{df1[column]}</td></tr>"
html_table += "</table>"
display(HTML(html_table))
Выходные данные:
Параметр | Ценность |
---|---|
Имя таблицы | sales_1 |
Число строк | 1000000000 |
Группы строк | двадцать четыре |
Файлы Parquet | 8 |
Максимальное количество строк для каждой группы строк | 51210000 |
Минимальные строки для каждой группы строк | 22580000 |
Среднее число строк для каждой группы строк | 41666666.666666664 |
Включено VOrder | Верно |
Общий размер | 7700808430 |
Метка времени | 2025-03-24 03:01:02.794979 |
Сводка Delta Analyzer показывает средний размер группы строк примерно в 40 миллионов строк. Это больше, чем рекомендуемый максимальный размер группы строк размером 16 миллионов строк. К счастью, больший размер группы строк не вызывает значительных проблем для Direct Lake. Более крупные группы строк способствуют выполнению непрерывных задач обработки сегментов с минимальным расходом в подсистеме хранилища. И наоборот, небольшие группы строк, которые значительно менее 1 миллиона строк, могут вызвать проблемы с производительностью.
Более важно в предыдущем примере то, что Fabric равномерно распределил группы строк между восемью файлами Parquet. Это соответствует количеству ядер архитектуры Fabric, необходимой для поддержки эффективных параллельных операций чтения. Кроме того, важно, чтобы отдельные размеры групп строк не отклонялись слишком далеко от среднего. Большие вариации могут привести к неуниформной нагрузке VertiScan, что приводит к снижению оптимальной производительности запросов.
Последовательное обновление окна
В целях иллюстрации следующий пример кода Python имитирует последовательное обновление окна. Код удаляет строки с самым старым идентификатором DateID из примера таблицы Delta. Затем он обновляет dateID этих строк и вставляет их обратно в пример таблицы в качестве последних строк.
from pyspark.sql.functions import lit
table_name = "<Provide your table name>"
table_df = spark.read.format("delta").load(f"Tables/{table_name}")
# Get the rows of the oldest DateID.
rows_df = table_df[table_df["DateID"] == 20200101]
rows_df = spark.createDataFrame(rows_df.rdd, schema=rows_df.schema)
# Delete these rows from the table
table_df.createOrReplaceTempView(f"{table_name}_view")
spark.sql(f"DELETE From {table_name}_view WHERE DateID = '20200101'")
# Update the DateID and append the rows as new data
rows_df = rows_df.withColumn("DateID", lit(20250101))
rows_df.write.format("delta").mode("append").save(f"Tables/{table_name}")
Функция get_delta_table_history
в библиотеке semantic-link-labs может помочь проанализировать эффект обновления скользящего окна. См. следующий пример кода Python. См. также таблицу с выходными данными после фрагмента кода.
import sempy_labs as labs
from IPython.display import HTML
from IPython.display import clear_output
table_name = "<Provide your table name>"
da_results = labs.get_delta_table_history(table_name)
# Create a single HTML table for specified columns
html_table = "<table border='1'>"
# Add data rows for specified columns
for index, row in da_results.iterrows():
for column in ['Version', 'Operation', 'Operation Parameters', 'Operation Metrics']:
if column == 'Version':
html_table += f"<tr><td><b>Version</b></td><td><b>{row[column]}</b></td></tr>"
else:
html_table += f"<tr><td>{column}</td><td>{row[column]}</td></tr>"
html_table += "</table>"
# Display the HTML table
display(HTML(html_table))
Выходные данные:
Версия | Описание | Ценность |
---|---|---|
2 | Операция | НАПИСАТЬ |
Параметры операции | {'mode': 'Append', 'partitionBy': '[]'} | |
Метрики операций | {'numFiles': "1", "numOutputRows": "548665", "numOutputBytes": "4103076"} | |
1 | Операция | Удалить |
Параметры операции | {'predicate': '["(DateID#3910 = 20200101)"]'} | |
Метрики операций | {'numRemovedFiles': "8", "numRemovedBytes": "7700855198", "numCopiedRows": "999451335", "numDeletionVectorsAdded": "0", "numDeletionVectorsRemoved": "0", "numAddedChangeFiles": "0", ExecutionTimeMs: "123446", "numDeletionVectorsUpdated": "0", "numDeletedRows": "548665", "scanTimeMs": "4820", "numAddedFiles": "18", "numAddedBytes": "7696900084", "rewriteTimeMs": "198625"} | |
0 | Операция | НАПИСАТЬ |
Параметры операции | {'mode': 'Overwrite', 'partitionBy': '[]'} | |
Метрики операций | {'numFiles': "8", "numOutputRows": "1000000000000", "numOutputBytes": "7700892169"} |
В журнале Delta Analyzer, приведенном выше, указано, что таблица Delta теперь содержит следующие три версии:
- Версия 0. Это исходная версия с восемью файлами Parquet и 24 группами строк, как описано в предыдущем разделе.
-
Версия 1. Эта версия отражает операцию удаления . Хотя из примера таблицы с пятью годами транзакций по продажам было удалено только однодневное значение данных (DateID = "20200101"), все восемь файлов Parquet были затронуты. В метриках операций
numRemovedFiles
— восемь [файлов Parquet], аnumAddedFiles
— 18 [файлов Parquet]. Это означает, что операция удаления заменила исходные восемь файлов Parquet на 18 новых файлов Parquet. - Версия 3. Метрики операций показывают, что в таблицу Delta добавлен еще один файл Parquet с 548 665 строками.
После обновления скользящего окна самая текущая версия фиксации Delta включает 19 файлов Parquet и 21 групп строк с размером от 500 тысяч до 50 миллионов строк. Обновление скользящего окна в 548 665 строк затронуло всю таблицу Delta из 1 миллиарда строк. Он заменил все файлы Parquet и группы строк. Добавочное обрамление не должно ожидаться для улучшения производительности в холодных условиях в этом случае, а увеличение вариации в размерах групп строк вряд ли принесет пользу производительности в разогретом состоянии.
Обновления Delta-таблицы
Следующий код Python обновляет таблицу Delta практически так же, как описано в предыдущем разделе. На первый взгляд, функция обновления изменяет исключительно значение DateID существующих строк, которые соответствуют заданному идентификатору DateID. Однако файлы Parquet неизменяемы и не могут быть изменены. Под поверхностью операция обновления удаляет существующие файлы Parquet и добавляет новые файлы Parquet. Результат и эффект такие же, как у обновления скользящего окна.
from pyspark.sql.functions import col, when
from delta.tables import DeltaTable
# Load the Delta table
table_name = "<Provide your table name>"
delta_table = DeltaTable.forPath(spark, f"Tables/{table_name}")
# Define the condition and the column to update
condition = col("DateID") == 20200101
column_name = "DateID"
new_value = 20250101
# Update the DateID column based on the condition
delta_table.update(
condition,
{column_name: when(condition, new_value).otherwise(col(column_name))}
)
Обновления секционированного скользящего окна
Секционирование может помочь уменьшить влияние обновлений таблиц. Может возникнуть соблазн использовать ключи даты, но быстрая проверка кардинальности может показать, что это не лучший выбор. Например, пример таблицы, рассмотренной до сих пор, содержит транзакции по продажам за последние пять лет, эквивалентные примерно 1800 значениям даты. Эта кратность слишком высока. Столбец раздела должен содержать менее 200 различных значений.
column_name = 'DateID'
table_name = "<Provide your table name>"
table_df = spark.read.format("delta").load(f"Tables/{table_name}")
distinct_count = table_df.select(column_name).distinct().count()
print(f"The '{column_name}' column has {distinct_count} distinct values.")
if distinct_count <= 200:
print(f"The '{column_name}' column is a good partitioning candidate.")
table_df.write.format("delta").partitionBy(column_name).save(f"Tables/{table_name}_by_date_id")
print(f"Table '{table_name}_by_date_id' partitioned and saved successfully.")
else:
print(f"The cardinality of the '{column_name}' column is possibly too high.")
Выходные данные:
The 'DateID' column has 1825 distinct values.
The cardinality of the 'DateID' column is possibly too high.
Если нет подходящего столбца для партиционирования, его можно создать искусственно, уменьшив кардинальность существующего столбца. Следующий код Python добавляет столбец «Месяц», удаляя последние две цифры DateID. Это создает 60 уникальных значений. Затем пример кода сохраняет таблицу Delta, секционированную столбцом "Месяц".
from pyspark.sql.functions import col, expr
column_name = 'DateID'
table_name = "sales_1"
table_df = spark.read.format("delta").load(f"Tables/{table_name}")
partition_column = 'Month'
partitioned_table = f"{table_name}_by_month"
table_df = table_df.withColumn(partition_column, expr(f"int({column_name} / 100)"))
distinct_count = table_df.select(partition_column).distinct().count()
print(f"The '{partition_column}' column has {distinct_count} distinct values.")
if distinct_count <= 200:
print(f"The '{partition_column}' column is a good partitioning candidate.")
table_df.write.format("delta").partitionBy(partition_column).save(f"Tables/{partitioned_table}")
print(f"Table '{partitioned_table}' partitioned and saved successfully.")
else:
print(f"The cardinality of the '{partition_column}' column is possibly too high.")
Выходные данные:
The 'Month' column has 60 distinct values.
The 'Month' column is a good partitioning candidate.
Table 'sales_1_by_month' partitioned and saved successfully.
Сводка Delta Analyzer теперь показывает, что макет таблицы Delta хорошо согласован с Direct Lake. Средний размер группы строк составляет около 16 миллионов строк, а среднее абсолютное отклонение размеров групп строк и, следовательно, размер сегмента меньше 1 миллиона строк.
Параметр | Ценность |
---|---|
Имя таблицы | продажи_1_по_месяцам |
Число строк | 1000000000 |
Группы строк | шестьдесят |
Файлы Parquet | шестьдесят |
Максимальное количество строк для каждой группы строк | 16997436 |
Минимальные строки для каждой группы строк | 15339311 |
Среднее число строк для каждой группы строк | 16666666.666666666 |
Включено VOrder | Верно |
Общий размер | 7447946016 |
Метка времени | 2025-03-24 03:01:02.794979 |
После обновления скользящего окна для секционированной выборочной таблицы история Delta Analyzer показывает, что был затронут только один файл Parquet. См. следующую таблицу выходных данных. Версия 2 имеет ровно 16 445 655 строк, скопированных из старого файла Parquet в замещающий файл Parquet, и версия 3 добавляет новый файл Parquet с 548 665 строками. В общей сложности Direct Lake требуется перезагрузить только около 17 миллионов строк, что значительно лучше по сравнению с перезагрузкой 1 миллиарда строк без секционирования.
Версия | Описание | Ценность |
---|---|---|
2 | Операция | НАПИСАТЬ |
Параметры операции | {'mode': 'Append', 'partitionBy': '["Месяц"]'} | |
Метрики операций | {'numFiles': "1", "numOutputRows": "548665", "numOutputBytes": "4103076"} | |
1 | Операция | Удалить |
Параметры операции | {'predicate': '["(DateID#3910 = 20200101)"]'} | |
Метрики операций | {'numRemovedFiles': "1", "numRemovedBytes": "126464179", "numCopiedRows": "16445655", "numDeletionVectorsAdded": "0", "numDeletionVectorsRemoved": "0", "numAddedChangeFiles": "0", "executionTimeMs": "19065", NumDeletionVectorsUpdated: "0", "numDeletedRows": "548665", "scanTimeMs": "1926", "numAddedFiles": "1", "numAddedBytes": "121275513", "rewriteTimeMs": "17138"} | |
0 | Операция | НАПИСАТЬ |
Параметры операции | {'mode': 'Overwrite', 'partitionBy': '["Месяц"]'} | |
Метрики операций | {'numFiles': "60", "numOutputRows": "100000000000", "numOutputBytes": "7447681467"} |
Шаблон только для добавления, за которым следует Spark Optimize
Шаблоны только для добавления не влияют на существующие файлы Parquet. Они хорошо работают с добавочным обрамлением Direct Lake. Однако не забудьте оптимизировать таблицы Delta для консолидации файлов Parquet и групп строк, как описано ранее в этой статье. Небольшие и частые добавления могут быстро накапливать файлы и могут искажать единообразие размеров групп строк.
В следующих результатах вывода показана история Delta Analyzer для неразделённой таблицы по сравнению с секционированной таблицей. История включает семь добавлений и одну последующую операцию оптимизации.
Версия | Описание | Значение в макете по умолчанию | Значение в секционированном макете |
---|---|---|---|
8 | Операция | ОПТИМИЗИРОВАТЬ | ОПТИМИЗИРОВАТЬ |
Параметры операции | {'predicate': '[]', 'auto': 'false', 'clusterBy': '[]', 'vorder': 'true', 'zOrderBy': '[]'} | {'predicate': '["('Month >= 202501)"], 'auto': 'false', 'clusterBy': '[]', 'vorder': 'true', 'zOrderBy': '[]'} | |
Метрики операций | {'numRemovedFiles': "8", "numRemovedBytes": "991234561", "p25FileSize": "990694179", NumDeletionVectorsRemoved: "0", "minFileSize": "990694179", "numAddedFiles": "1", "maxFileSize": "990694179", "p75FileSize": "990694179", "p50FileSize": "990694179", "numAddedBytes": "990694179"} | {'numRemovedFiles': "7", "numRemovedBytes": "28658548", "p25FileSize": "28308495", NumDeletionVectorsRemoved: "0", "minFileSize": "28308495", "numAddedFiles": "1", "maxFileSize": "28308495", "p75FileSize": "28308495", "p50FileSize": "28308495", "numAddedBytes": "28308495"} | |
7 | Операция | НАПИСАТЬ | НАПИСАТЬ |
Параметры операции | {'mode': 'Append', 'partitionBy': '[]'} | {'mode': 'Append', 'partitionBy': '["Месяц"]'} | |
Метрики операций | {'numFiles': '1', 'numOutputRows': '547453', 'numOutputBytes': '4091802'} | {'numFiles': '1', 'numOutputRows': '547453', 'numOutputBytes': '4091802'} | |
6 | Операция | НАПИСАТЬ | НАПИСАТЬ |
Параметры операции | {'mode': 'Append', 'partitionBy': '[]'} | {'mode': 'Append', 'partitionBy': '["Месяц"]'} | |
Метрики операций | {'numFiles': "1", "numOutputRows": "548176", "numOutputBytes": "4095497"} | {'numFiles': "1", "numOutputRows": "548176", "numOutputBytes": "4095497"} | |
5 | Операция | НАПИСАТЬ | НАПИСАТЬ |
Параметры операции | {'mode': 'Append', 'partitionBy': '[]'} | {'mode': 'Append', 'partitionBy': '["Месяц"]'} | |
Метрики операций | {'numFiles': '1', 'numOutputRows': '547952', 'numOutputBytes': '4090107'} | {'numFiles': "1", "numOutputRows": "547952", "numOutputBytes": "4093015"} | |
4 | Операция | НАПИСАТЬ | НАПИСАТЬ |
Параметры операции | {'mode': 'Append', 'partitionBy': '[]'} | {'mode': 'Append', 'partitionBy': '["Месяц"]'} | |
Метрики операций | {'numFiles': '1', 'numOutputRows': '548631', 'numOutputBytes': '4093134'} | {'numFiles': "1", "numOutputRows": "548631", "numOutputBytes": "4094376"} | |
3 | Операция | НАПИСАТЬ | НАПИСАТЬ |
Параметры операции | {'mode': 'Append', 'partitionBy': '[]'} | {'mode': 'Append', 'partitionBy': '["Месяц"]'} | |
Метрики операций | {'numFiles': "1", "numOutputRows": "548671", "numOutputBytes": "4101221"} | {'numFiles': "1", "numOutputRows": "548671", "numOutputBytes": "4101221"} | |
2 | Операция | НАПИСАТЬ | НАПИСАТЬ |
Параметры операции | {'mode': 'Append', 'partitionBy': '[]'} | {'mode': 'Append', 'partitionBy': '["Месяц"]'} | |
Метрики операций | {'numFiles': '1', 'numOutputRows': '546530', 'numOutputBytes': '4081589'} | {'numFiles': '1', 'numOutputRows': '546530', 'numOutputBytes': '4081589'} | |
1 | Операция | НАПИСАТЬ | НАПИСАТЬ |
Параметры операции | {'mode': 'Append', 'partitionBy': '[]'} | {'mode': 'Append', 'partitionBy': '["Месяц"]'} | |
Метрики операций | {'numFiles': "1", "numOutputRows": "548665", "numOutputBytes": "4101048"} | {'numFiles': "1", "numOutputRows": "548665", "numOutputBytes": "4101048"} | |
0 | Операция | НАПИСАТЬ | НАПИСАТЬ |
Параметры операции | {'mode': 'Overwrite', 'partitionBy': '[]'} | {'mode': 'Overwrite', 'partitionBy': '["Месяц"]'} | |
Метрики операций | {'numFiles': '8', 'numOutputRows': '100000000000', "numOutputBytes": '7700855198'} | {'numFiles': "60", "numOutputRows": "100000000000", "numOutputBytes": "7447681467"} |
Глядя на метрики работы версии 8, стоит отметить, что операция оптимизации для неразделённых таблиц объединяла восемь файлов Parquet, затрагивающих приблизительно 1 ГБ данных, в то время как оптимизация разделённых таблиц объединила семь файлов Parquet, затрагивающих только около 25 МБ данных. Ниже показано, что Direct Lake лучше будет работать с секционированной таблицей.
Соображения и ограничения
Рекомендации и ограничения оптимизации производительности Direct Lake приведены ниже.
- Избегайте разрушительных шаблонов обновления в больших таблицах Delta, чтобы сохранить инкрементальный фрейминг в Direct Lake.
- Небольшие разностные таблицы не нужно оптимизировать для добавочного обрамления.
- Нацелитесь на группу строк размером от 1 до 16 миллионов строк, чтобы создать сегменты столбцов в Direct Lake с 1 млн до 16 миллионов строк. Direct Lake предпочитает большие сегменты столбцов.
- Избегайте столбцов секций с высокой кардинальностью, так как транскодирование Direct Lake менее эффективно при обработке большого количества небольших файлов Parquet и групп строк, чем при обработке меньшего количества больших файлов Parquet и групп строк.
- Из-за непредвиденного спроса на вычислительные ресурсы и ресурсы памяти семантическая модель может быть перезагружена на другой узел кластера Fabric в холодном состоянии.
- Direct Lake не использует статистику delta/Parquet для пропуска групп строк/файлов, чтобы оптимизировать загрузку данных.