💎

【Rails】activerecord-importで発行されるSQL

2024/08/16に公開

はじめに

本記事では、activerecord-importというGemを使用した場合と使用しない場合のSQLの違いとその影響について解説します。activerecord-importは、大量のデータを効率的にデータベースに挿入するためのツールであり、特にパフォーマンスの向上が期待できます。これを利用することで、データベース操作の最適化が可能になります。

activerecord-importを使用する場合と使用しない場合のSQLの違い

activerecord-importを使用する場合と使用しない場合のSQLの違いは、主に以下の4つです。

  1. SQL文の数
  2. トランザクション
  3. バリデーションとユニーク制約の処理
  4. パフォーマンス

SQL文の数

使用しない場合

通常のActiveRecordを使用すると、各レコードごとに個別のINSERT文が生成されます。例えば、100件のレコードを挿入する場合、100個のINSERT文が実行されます。

INSERT INTO books (title, author) VALUES ('Book 1', 'Author 1');
INSERT INTO books (title, author) VALUES ('Book 2', 'Author 2');
...
INSERT INTO books (title, author) VALUES ('Book 100', 'Author 100');

使用する場合

activerecord-importを使用すると、一つのINSERT文で複数のレコードを挿入できます。このため、SQL文の数が大幅に減少します。

INSERT INTO books (title, author) VALUES 
('Book 1', 'Author 1'),
('Book 2', 'Author 2'),
...
('Book 100', 'Author 100');

トランザクション

使用しない場合

通常のActiveRecordを使用すると、各INSERT文が個別のトランザクションとして処理されることがあります。

BEGIN;
INSERT INTO books (title, author) VALUES ('Book 1', 'Author 1');
COMMIT;

BEGIN;
INSERT INTO books (title, author) VALUES ('Book 2', 'Author 2');
COMMIT;

使用する場合

activerecord-importを使用すると、全てのINSERT文を一つのトランザクションでまとめて実行することが可能です。

BEGIN;
INSERT INTO books (title, author) VALUES 
('Book 1', 'Author 1'),
('Book 2', 'Author 2'),
...
('Book 100', 'Author 100');
COMMIT;

バリデーションとユニーク制約の処理

使用しない場合

通常のActiveRecordを使用すると、各レコードごとに個別にバリデーションが実行され、ユニーク制約のチェックも個別に行われます。

SELECT 1 FROM books WHERE title = 'Book 1' LIMIT 1;
INSERT INTO books (title, author) VALUES ('Book 1', 'Author 1');

SELECT 1 FROM books WHERE title = 'Book 2' LIMIT 1;
INSERT INTO books (title, author) VALUES ('Book 2', 'Author 2');

使用する場合

activerecord-importでは、バリデーションをスキップするオプションがあり、データベース側でユニーク制約を処理することも可能です。これにより、パフォーマンスがさらに向上します。

INSERT INTO books (title, author) VALUES 
('Book 1', 'Author 1'),
('Book 2', 'Author 2')
ON CONFLICT (title) DO NOTHING;

パフォーマンス

activerecord-importを使用することで、大量のデータを挿入する際のパフォーマンスが大幅に向上します。例えば、50万行のデータを挿入する場合、通常のActiveRecordを使用すると数時間かかる処理が、activerecord-importを使用すると3分以内に完了したという報告もあります。

こうした違いにより、activerecord-importは大量のデータを効率的に挿入する必要がある場合に特に有効です。ただし、小規模なデータセットや、個々のレコードに対して複雑な処理が必要な場合は、通常のActiveRecordの方が適している場合もありそうです。

参考資料

https://medium.com/@eric_lum/importing-large-datasets-in-ror-why-you-should-use-activerecord-import-26fc915e6fd0
https://stackoverflow.com/questions/15603454/how-does-activerecord-import-gem-deal-with-concurrent-imports-does-it-lock-the
https://github.com/zdennis/activerecord-import
https://naturaily.com/blog/ruby-on-rails-fast-data-import
https://reinteractive.com/articles/importing-data-faster-with-activerecord-import

Discussion