
高速と噂される SQL リンターツール「sqruff」を実際に試してみた
Google Cloud データエンジニアのはんざわです。
皆さん、SQL のリンターを使っていますか?
過去のブログで SQL のリンターである sqlfluff を紹介しましたが、本ブログでは、sqlfluff よりも高速と噂される新しいツール「sqruff」を試してみたいと思います。
(余談ですが、この「sqruff」ってどう発音するんでしょうね、SQL + Ruff で「エスキューラフ」?それとも別の発音?)
検証環境
- OS とバージョン
- macOS 13.5.2
- パッケージ管理システム
- Homebrew 4.4.8
- SQL の方言
- BigQuery
sqruff とは?
sqruff は、Rust で開発された SQL リンターおよびフォーマッターのオープンソースツールです。
似たようなツールとして sqlfluff がありますが、sqruff はその sqlfluff よりも高速だと噂されています。
投稿日時点では、以下の SQL の方言に対応しています。将来的には、さらに多くの方言がサポートされる予定とのことです。
ANSI SQL(デフォルト)BigQueryAthenaClickhouseDuckDBPostgreSQLSnowflakeSparkSqlSQLiteTrino
ローカル環境で触ってみる
本ブログでは、ローカル環境で sqruff を実際に試してみます。
インストール
brew install コマンドを使って sqruff をインストールします。以下のコマンドを実行します。
$ brew install quarylabs/quary/sqruff
インストール後、バージョンの確認を行い、正常にインストールされているか確認します。
$ sqruff --version
> sqruff 0.20.2
機能の概要
sqruff には、主に以下の 2 つの機能があります。
- lint:SQL を読み込み、事前に定義されたルールに沿って問題点を指摘します。
- fix:問題点を指摘するだけでなく、SQL クエリを修正します。
これらの動作は sqlfluff とほとんど同じため、すでに sqlfluff を使ったことがある方には馴染みやすいツールだと思います。
sqruff コマンドの詳細については、以下のドキュメントを参考にしてください。
本ブログでは、lint の機能を試してみます。
ルールファイルの作成
まずは、sqruff のルールファイルを作成します。
ルール設定は .sqruff ファイルで行い、このファイルを sqruff コマンドを実行するディレクトリに配置します。
sqlfluff を使ったことがある方は、sqruff のルールファイルが sqlfluff の .sqlfluff ファイルと非常に似ているため、ほぼ同じ感覚で設定できると思います。
以下は、例として作成した .sqruff ファイルです。この設定では、SQL 方言を BigQuery に指定し、AM01 と AM02 を除くすべてのルールを有効にしています。
[sqruff]
dialect = bigquery
rules = all
exclude_rules = AM01,AM02
[sqruff:indentation]
indent_unit = space
tab_space_size = 4
ルール名(例:AM01, AM02)や各ルールの詳細については、以下のドキュメントを参考にしてください。
また、ルールファイルで設定できる項目(例:dialect, rules など)の一覧については、以下のドキュメントを参考にしてください。
動かしてみる
次に、フォーマットが乱れているサンプルの SQL ファイルを用意します。
with temp AS (
SELECT *
FROM sample.test
)
selecT id,
hoge,
ifnull(fuga, '')
FROM
temp t
.sqruff ファイルが配置されているディレクトリで、以下のコマンドを実行します。
$ sqruff lint sql/sample.sql
結果は以下の通りです。
== [sql/sample.sql] FAIL
L: 1 | P: 11 | CP01 | Keywords must be consistently lower case.
| [capitalisation.keywords]
L: 2 | P: 5 | CP01 | Keywords must be consistently lower case.
| [capitalisation.keywords]
L: 2 | P: 11 | LT01 | Expected only single space before "*". Found " ".
| [layout.spacing]
L: 3 | P: 5 | CP01 | Keywords must be consistently lower case.
| [capitalisation.keywords]
L: 6 | P: 1 | CP01 | Keywords must be consistently lower case.
| [capitalisation.keywords]
L: 6 | P: 1 | LT09 | Select targets should be on a new line unless there is
| only one select target.
| [layout.select_targets]
L: 6 | P: 7 | LT02 | Expected line break and indent of 4 spaces before "id".
| [layout.indent]
L: 7 | P: 1 | LT02 | Expected indent of 4 spaces
| [layout.indent]
L: 8 | P: 1 | LT02 | Line should not be indented.
| [layout.indent]
L: 8 | P: 3 | AL03 | Column expression without alias. Use explicit `AS`
| clause. [aliasing.expression]
L: 8 | P: 3 | CV02 | Use 'COALESCE' instead of 'IFNULL'.
| [convention.coalesce]
L: 9 | P: 1 | CP01 | Keywords must be consistently lower case.
| [capitalisation.keywords]
L: 10 | P: 1 | LT02 | Expected indent of 4 spaces.
| [layout.indent]
L: 10 | P: 8 | AL01 | Implicit/explicit aliasing of table.
| [aliasing.table]
L: 10 | P: 8 | AL05 | Alias 't' is never used in SELECT statement.
| [aliasing.unused]
The linter processed 1 file(s).
All Finished 📜 🎉
結果を見ると、ルール違反の箇所がリストアップされています。
L は行番号、P は文字位置を表しています。この例では、次のように修正することでインデントのチェックをパスできます。
with temp as (
select *
from
sample.test
)
select
t.id,
t.hoge,
coalesce(t.fuga, '') as fuga
from
temp as t
再度、lint を実行すると、問題が解消されていることが確認できます。
$ sqruff lint sql/sample.sql
The linter processed 1 file(s).
All Finished 📜 🎉
このように、sqruff は sqlfluff と同じ感覚で簡単に利用できます。
おまけ:sqlfluff と速度を比較してみる
上記の公式ブログによると、sqruff は sqlfluff と比較して高速であると紹介されています。
実際にどれほどの差があるのか、行数の異なる SQL ファイルを用意して検証してみました。
検証の環境
検証に使用したバージョンは以下の通りです。
$ sqlfluff --version
> sqlfluff, version 3.2.5
$ sqruff --version
> sqruff 0.20.2
また、.sqlfluff と .sqruff のルールファイルは統一しています。
[sqlfluff]
dialect = bigquery
rules = all
[sqlfluff:indentation]
indent_unit = space
tab_space_size = 4
[sqruff]
dialect = bigquery
rules = all
[sqruff:indentation]
indent_unit = space
tab_space_size = 4
各リンターの速度は、以下のコマンドで計測しました。
それぞれのコマンドを 3 回ずつ実行し、速度を比較してみたいと思います。
# sqlfluff lint
start=$(gdate +%s.%N); sqlfluff lint sql/; end=$(gdate +%s.%N); echo "Execution time: $(printf "%.2f" $(echo "$end - $start" | bc)) seconds"
# sqruff lint
start=$(gdate +%s.%N); sqruff lint sql/; end=$(gdate +%s.%N); echo "Execution time: $(printf "%.2f" $(echo "$end - $start" | bc)) seconds"
検証の結果
- 行数小さいクエリ
まずは、行数が小さいクエリで試してみます。
行数が 25 で文字数が 636 のファイルを 10 個用意しました。
$ find ./short_sql -type f -exec wc -l -m {} +
25 636 ./short_sql/sample_5.sql
25 636 ./short_sql/sample_4.sql
25 636 ./short_sql/sample_6.sql
25 636 ./short_sql/sample_7.sql
25 636 ./short_sql/sample_3.sql
25 636 ./short_sql/sample_2.sql
25 636 ./short_sql/sample_1.sql
25 636 ./short_sql/sample_10.sql
25 636 ./short_sql/sample_9.sql
25 636 ./short_sql/sample_8.sql
250 6360 total
3 回実行した結果は以下の通りです。sqruff の方が sqlfluff と比べて約 10 倍高速であることが確認できました。
| sqlfluff | sqruff | |
|---|---|---|
| 1 回目 | 0.92 | 0.12 |
| 2 回目 | 0.92 | 0.10 |
| 3 回目 | 0.93 | 0.09 |
- 行数が大きいクエリ
次に、行数が大きいクエリで試してみます。
行数が 180 で文字数が 8460 のファイルを 10 個用意しました。
$ find ./long_sql -type f -exec wc -l -m {} +
180 8460 ./long_sql/sample_5.sql
180 8460 ./long_sql/sample_4.sql
180 8460 ./long_sql/sample_6.sql
180 8460 ./long_sql/sample_7.sql
180 8460 ./long_sql/sample_3.sql
180 8460 ./long_sql/sample_2.sql
180 8460 ./long_sql/sample_1.sql
180 8460 ./long_sql/sample_10.sql
180 8460 ./long_sql/sample_9.sql
180 8460 ./long_sql/sample_8.sql
1800 84600 total
3 回実行した結果は以下の通りです。行数が小さいクエリで見られたほどの差はなく、sqlfluff と sqruff の速度は比較的近い結果となりました。
| sqlfluff | sqruff | |
|---|---|---|
| 1 回目 | 4.21 | 3.55 |
| 2 回目 | 4.19 | 3.72 |
| 3 回目 | 4.30 | 3.70 |
考察
以下の Issue にも報告されているように、ファイルの行数が増えると sqruff のパフォーマンスが指数関数的に低下する現象が確認されています。さらに、SQL 方言が BigQuery の場合、他の方言よりもパフォーマンスが悪化する傾向があるようです。
プロジェクトによって SQL ファイルの行数や規模は異なると思いますが、今回の検証では以下のような特徴が確認できました。
- sqruff は、小さいクエリファイルを多数処理する場合に特に高速
- sqlfluff は、大規模なクエリファイルを安定して処理できる点が魅力
この検証結果は、ローカル環境で SQL の方言を BigQuery に設定した場合のものです。例えば、GitHub Actions(GHA)などの CI 環境や、他の SQL 方言を使用する場合には、異なる結果となる可能性があります。
これらの条件によってパフォーマンスがどう変化するかは、別途検証が必要です。
感想
今回のブログでは、sqruff を実際に触ってみました。
sqlfluff は、すでにある程度成熟したツールとして広く利用されているように思います。
一方で、sqruff はまだ発展途上のツールですが、その高速性は非常に魅力的で、これからさらに成長していく可能性があると感じています。
また、投稿日時点で dbt の方言はサポートされていませんが、上記の Issue にもある通り、今後対応していく動きもあります。これからのアップデートにも目が離せませんね。








