Перейти к основному содержимому

О команде dbt lint

dbt lint — это быстрый SQL-линтер, встроенный в dbt v2 и доступный локально или на dbt platform. Для dbt lint требуется версия v2 или более поздняя. Если вы используете более раннюю версию, обновите или установите dbt.

Он совместим с SQLFluff: читает вашу конфигурацию .sqlfluff, использует те же коды правил (например, CP01, RF03) и учитывает комментарии подавления -- noqa. Совместимость не означает идентичность: dbt lint и SQLFluff могут возвращать разные результаты для одного и того же файла с одной и той же конфигурацией. См. раздел Соответствие правил SQLFluff.

Вы можете использовать существующую конфигурацию SQLFluff с минимальными изменениями. В дальнейшем dbt Labs планирует следовать актуальной спецификации правил SQLFluff.

примечание

dbt lint входит в состав dbt v2 и отличается от dbt sqlfluff lint в dbt platform CLI. Подробнее о SQLFluff в platform CLI см. в разделе Настройка dbt platform CLI. Линтинг в Studio IDE по-прежнему использует SQLFluff.

Тесты производительности​

На проектах размером от 1 тыс. до 10 тыс. моделей dbt lint работает в 40–250 раз быстрее SQLFluff при использовании всех ядер и в 280–1500 раз быстрее SQLFluff в однопоточном режиме.

dbt Labs провела эти тесты с SQLFluff 4.2.1 на проектах dbt с диалектом Snowflake, содержащих от 1 тыс. до 10 тыс. моделей, на MacBook Pro с 12-ядерным процессором Apple M4 Pro и 24 ГБ оперативной памяти.

Использование​

dbt lint [FILE] [flags]

[FILE] — необязательный аргумент. Если не указать [FILE], dbt lint проверит все SQL-файлы в вашем проекте.

Флаги​

ФлагОписание
--fixАвтоматически исправляет нарушения правил, для которых доступно автоматическое исправление. Правила, нарушения которых нельзя исправить автоматически, перечислены в разделе Правила без автоматического исправления.
--config <path>Путь к файлу конфигурации .sqlfluff. Переопределяет автоматическое обнаружение.
--rulesСписок кодов правил для включения, разделённых запятыми. Переопределяет конфигурацию.
--exclude-rulesСписок кодов правил для отключения, разделённых запятыми. Переопределяет конфигурацию.
--changedПроверяет только файлы, изменённые в текущем рабочем дереве git.
--format human|json|github-annotationФормат вывода. По умолчанию — human. Используйте json для машиночитаемого вывода или github-annotation для интеграции с GitHub Actions.
--jinja-render-mode <mode>Способ рендеринга Jinja в dbt lint перед проверкой. Допустимые значения: symbolic (по умолчанию), rendered или turbo. Переопределяет конфигурацию .sqlfluff. См. раздел Режимы рендеринга Jinja.

Конфигурация​

dbt lint автоматически обнаруживает ближайший файл .sqlfluff в дереве каталогов вашего проекта. Флаги CLI --rules и --exclude-rules имеют приоритет над значениями в файле конфигурации. О создании файла .sqlfluff см. в разделе Файлы конфигурации SQLFluff.

Требование к шаблонизатору​

dbt lint и dbt format поддерживают только шаблонизатор SQLFluff dbt, но не jinja. Явно укажите шаблонизатор в файле .sqlfluff:

[sqlfluff]
templater = dbt

Если в файле .sqlfluff не задано templater = dbt, при каждом запуске в журнал записывается следующее предупреждение, но выполнение всё равно продолжается:

[warning] [NotSupported (dbt9000)]: SQLFluff templater 'jinja' is not supported. dbt lint/format only supports SQLFluff templater 'dbt'. Continuing anyway.

Установка templater = dbt устраняет это предупреждение.

Правила, специфичные для dbt​

dbt lint также включает пять правил, специфичных для dbt, с префиксом кода DBT. Эти правила выявляют особенности использования dbt, которые не обнаруживает обычный SQL-линтер, например жёстко заданные имена отношений вместо ref().

По умолчанию эти правила отключены. Чтобы включить их, добавьте строку rules в файл .sqlfluff:

[sqlfluff]
templater = dbt
dialect = your_dialect
rules = DBT02,DBT03,DBT04,DBT05
КодИмя с точечной нотациейПравило
DBT01dbt.import_ctesКаждый вызов ref()/source() должен импортироваться через CTE верхнего уровня, а не использоваться непосредственно в запросе
DBT02dbt.join_condition_orУсловие ON в JOIN не должно содержать OR
DBT03dbt.function_wrapped_filter_columnВ сравнении ссылка на столбец не должна быть обёрнута в вызов функции
DBT04dbt.leading_wildcard_likeШаблон LIKE/ILIKE не должен начинаться с подстановочного символа
DBT05dbt.hard_coded_referenceСсылка ref()/source() не должна быть жёстко задана строковым литералом

Режимы рендеринга Jinja​

Прежде чем dbt lint сможет проверить модель, ему нужно преобразовать SQL с шаблонами Jinja в обычный SQL. Большинство шаблонов Jinja корректно обрабатываются во время линтинга, но некоторые макросы запрашивают информацию у вашей платформы данных, например список столбцов таблицы. При этом dbt lint никогда не подключается к платформе, поэтому такие вызовы не получают реального ответа. Настройка jinja_render_mode определяет, как dbt lint обрабатывает эти вызовы, и от неё зависит, какие нарушения вы увидите.

Для большинства проектов рекомендуется оставить значение по умолчанию — symbolic. Доступны три режима:

РежимКраткое описание
symbolic (по умолчанию)Выполняет обычный рендеринг Jinja и подставляет заполнитель вместо результатов, которые невозможно получить от платформы.
renderedВыполняет рендеринг Jinja с пустыми значениями-заглушками, никак не отмечая, что они подставные.
turboПолностью пропускает выполнение и проверяет буквальный текст шаблона.

Symbolic (по умолчанию)​

Выполняет Jinja, но отслеживает, какие значения получены из интроспективных вызовов адаптера, таких как adapter.execute, adapter.get_relation и adapter.get_columns_in_relation. Поскольку во время линтинга эти вызовы не могут обратиться к хранилищу данных, dbt lint заменяет их результат заполнителем, а не вводящим в заблуждение пустым значением. Всё остальное обрабатывается как обычно.

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

Например, модель, которая перебирает результат интроспективного вызова:

{% set cols = adapter.get_columns_in_relation(ref('orders')) %}
select {{ cols | map(attribute='name') | join(', ') }}
from {{ ref('orders') }}

для целей линтинга преобразуется примерно в следующее:

select your_columns
from orders

dbt lint не сообщает о нарушениях в самом значении-заполнителе, но проверяет всё остальное в запросе как обычно.

Rendered​

Выполняет Jinja со значениями-заглушками, используемыми на этапе разбора. Интроспективные вызовы адаптера возвращают пустые результаты без каких-либо указаний на то, что эти значения не настоящие, поэтому та же модель преобразуется в:

select
from orders

Пустой список select может привести к появлению SQL, который ваш проект никогда не выполнил бы, и dbt lint проверяет именно этот нереалистичный результат. Сравните rendered с symbolic, если разбираетесь с неожиданным нарушением.

Turbo​

Никогда не выполняет Jinja. Анализирует синтаксис шаблона, сохраняет написанный вами SQL как есть и заменяет каждое выражение {{ ... }} заполнителем, в том числе выражения, не связанные с интроспекцией:

select your_expression
from your_expression

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

Настройка режима рендеринга​

Задайте режим для отдельного запуска с помощью --jinja-render-mode. Флаг работает как с dbt lint, так и с dbt format:

dbt lint --jinja-render-mode rendered
dbt format --jinja-render-mode turbo

Задайте его для всего проекта в секции [dbt] файла .sqlfluff:

[dbt]
jinja_render_mode = rendered

Флаг CLI имеет приоритет над файлом конфигурации.

Варианты рендеринга​

В режимах symbolic и turbo одна модель может давать несколько возможных вариантов SQL. Когда dbt lint доходит до блока {% if %}, условие которого не удаётся вычислить, он проверяет несколько ветвей, а не пытается угадать, какую из них вы имели в виду. Каждый такой результат называется вариантом рендеринга, и dbt lint сообщает о нарушениях, найденных во всех этих вариантах.

render_variant_limit ограничивает число вариантов, которые dbt lint создаёт для каждой модели; значение по умолчанию — 5. Задайте его в секции [sqlfluff] файла .sqlfluff:

[sqlfluff]
render_variant_limit = 10

Увеличение лимита расширяет охват проверки, но увеличивает время линтинга, поскольку каждый дополнительный вариант требует ещё одного рендеринга шаблона. Уменьшение значения до 1 ограничивает dbt lint одним вариантом для каждой модели.

Игнорирование файлов и каталогов​

Используйте файл .sqlfluffignore в корне проекта, чтобы исключить пути, которые вы пока не готовы проверять, например dbt_packages/ или models/legacy/.

.sqlfluffignore использует синтаксис в стиле .gitignore. Полный справочник по шаблонам см. в документации SQLFluff по .sqlfluffignore.

# .sqlfluffignore
dbt_packages/
models/legacy/
snapshots/

Когда будете готовы проверять эти пути, удалите соответствующие записи из .sqlfluffignore.

Уменьшение количества лишних сообщений на вкладке Problems в Studio IDE​

Studio IDE автоматически проверяет SQL и показывает нарушения на вкладке Problems. Если вы видите много предупреждений о стиле и пока не готовы их исправлять, добавьте каталоги моделей в .sqlfluffignore, чтобы сразу убрать эти нарушения с вкладки Problems. По мере устранения нарушений постепенно удаляйте записи об игнорировании.

Подавление нарушений​

dbt lint поддерживает полный синтаксис подавления SQLFluff:

ПодавлениеОбласть действия
-- noqaПодавляет все нарушения в строке
-- noqa: CP01, RF03Подавляет указанные правила в этой строке
-- noqa-fileПодавляет все нарушения в файле
-- sqlfluff:disable CP01Отключает правило в файле

Поддерживаемые диалекты​

В настоящее время dbt lint поддерживает следующие диалекты:

  • Snowflake
  • BigQuery
  • DuckDB
  • Redshift
  • Databricks
  • SparkSQL (сейчас является псевдонимом Databricks)

Поддержка дополнительных диалектов появится в ближайшее время.

dbt format​

Для dbt format (также доступной как dbt fmt) требуется версия v2 или более поздняя. Команда автоматически форматирует SQL-файлы в соответствии с правилами оформления (LT*) из файла .sqlfluff. В отличие от dbt lint, она не выводит диагностические сообщения. При запуске команда применяет исправления без вывода сообщений, непосредственно в файлах.

dbt format [FILE] [flags]
dbt fmt [FILE] [flags]

[FILE] — необязательный аргумент. Если его не указать, dbt format отформатирует все SQL-файлы в проекте. Вы также можете передать отдельный файл или каталог, чтобы ограничить область выполнения.

Если в .sqlfluff не задано templater = dbt, dbt format записывает предупреждение в журнал и продолжает работу. См. раздел Требование к шаблонизатору.

Флаги форматирования​

ФлагОписание
--checkПроверяет форматирование файлов, не записывая изменения. Завершается с ненулевым кодом, если хотя бы один файл не отформатирован. Никогда не изменяет файлы.
--layout KEY=VALUE, -l KEY=VALUEПереопределяет правила оформления в стиле SQLFluff для текущего запуска. Повторите флаг, чтобы задать несколько параметров. См. раздел Параметры оформления.
--jinja-render-mode MODEЗадаёт способ рендеринга Jinja в dbt format перед форматированием. Допустимые значения: symbolic (по умолчанию), rendered или turbo. См. раздел Режимы рендеринга Jinja.

Параметры оформления​

Флаг --layout принимает пары KEY=VALUE и переопределяет соответствующие правила оформления из файла .sqlfluff для одного запуска. Он переопределяет только переданные ключи; все остальные правила оформления dbt format по-прежнему читает из файла .sqlfluff. Поддерживаются следующие ключи:

КлючОписание
indent=NUMBERЗадаёт число пробелов для отступа.
commas=leading|trailingЗадаёт расположение запятых.
line-length=NUMBERЗадаёт максимальную длину строки.

Например, чтобы отформатировать код с запятыми в начале строк и отступом в два пробела:

dbt format -l commas=leading -l indent=2

Проверка форматирования в CI​

Используйте --check для проверки без внесения изменений, чтобы разрешать принятие pull request только при соблюдении форматирования. Если все файлы отформатированы, команда завершается с кодом 0. Если какой-либо файл не отформатирован, команда завершается с кодом 1, оставляет файл без изменений и возвращает ошибку следующего вида:

[error] [Generic (dbt1000)]: Formatting check failed for models/staging/stg_orders.sql. Run `dbt fmt` to format it.
dbt format --check                                # check all SQL files
dbt format --check models/staging # check a directory
dbt format --check models/staging/stg_orders.sql # check a single file

Чтобы устранить ошибки проверки, запустите dbt format без --check.

Соответствие правил SQLFluff​

dbt lint стремится обеспечить высокую степень соответствия SQLFluff, но не гарантирует полного совпадения по каждому правилу, и небольшие различия будут существовать всегда. Одна из известных областей различий — правила оформления и отступов, такие как LT02.

Поскольку линтинг в Studio IDE по-прежнему использует SQLFluff, действие Lint file в Studio IDE и команда dbt lint могут сообщать о разных нарушениях в одном и том же коде проекта. Аналогично, задания CI, использующие версию dbt v2, вызывают dbt lint вместо SQLFluff, поэтому результаты заданий CI могут отличаться от результатов SQLFluff.

Если вам нужно поведение SQLFluff, вы можете выполнять линтинг в Studio IDE, где по-прежнему используется SQLFluff, либо запускать SQLFluff локально с шаблонизатором для отдельного движка dbt v1. Дополнительные сведения см. в разделе Ограничения dbt v2.

Преобразование предупреждений линтера в ошибки​

По умолчанию нарушения правил без автоматического исправления отображаются как предупреждения и не приводят к завершению dbt lint с ошибкой. Нарушения, которые можно исправить с помощью --fix, отображаются как ошибки и приводят к завершению команды с ошибкой.

Если вы хотите, чтобы нарушение правила отображалось как ошибка, а не предупреждение, добавьте имя правила в warn_error_options в файле dbt_project.yml. Имя правила можно найти в выводе линтера. Например, правило ST05 отображается как PreferCTE:

flags:
warn_error_options:
error:
- PreferCTE

Если вместо этого задать error: all, dbt преобразует в ошибки все предупреждения, в том числе предупреждения команд, отличных от lint:

flags:
warn_error_options:
error: all

Чтобы преобразовать в ошибку нарушение одного правила линтера, укажите имя этого правила, как в первом примере. См. раздел Предупреждения.

В задании CI флажок Linting запускает dbt lint с использованием этого файла проекта. Выберите Stop running on error, чтобы задание завершалось с ошибкой, когда линтер сообщает об ошибке. О включении линтинга см. в разделах Настройка заданий CI и Линтинг SQL.

Ограничения​

Учитывайте следующие ограничения:

Правила без автоматического исправления​

Следующие правила сообщают о нарушениях, но не поддерживают автоматическое исправление с помощью --fix. Для их исправления требуется изменить порядок SQL-фрагментов или более существенно переработать их размещение, что механизм сопоставления с исходным кодом (на основе macro_spans) не может безопасно выполнить внутри SQL с шаблонами Jinja:

  • Псевдонимы: AL03, AL04, AL06, AL08
  • Ссылки: RF01, RF02, RF04, RF05
  • Структура: ST03, ST04, ST05, ST06, ST07, ST09, ST10, ST11
  • Неоднозначность / соглашения: AM01, AM06, CV08, CV09, CV12

Чтобы выполнение завершалось с ошибкой при нарушении одного из этих правил, см. раздел Преобразование предупреждений линтера в ошибки.

Один проход исправлений​

--fix выполняет один проход и не повторяет его до устранения всех нарушений в файле. Исправление, применённое одним правилом, может выявить нарушение другого правила при следующем запуске. Например, AL09 удаляет псевдоним, совпадающий с исходным именем, после чего RF02 может отметить ссылку, которая теперь не содержит квалификатора. Повторно запускайте dbt lint --fix, пока в выводе не останется нарушений.

Часто задаваемые вопросы​

 Почему dbt lint не проверяет все возможные результаты моего шаблона Jinja?
 Почему dbt lint не сообщает о нарушениях в некоторых макросах?

Обратная связь​

Если вы столкнулись с неожиданным поведением или у вас есть предложения, создайте issue в репозитории dbt-labs/dbt на GitHub и добавьте метку Linter.

Нашли ошибку?

0
Loading