Rails 並列処理でCSVをDBにインサート:外部キー制約のエラーを回避する
IT技術
はじめに
大量のCSVデータをRailsのモデルを通じてデータベースにインサートする際に、外部キー制約(Foreign Key Constraints)によるエラーが発生したことはありませんか?この記事では、Railsアプリケーションで外部キー制約のエラーを回避する方法を説明します。
背景
Railsを使ったデータインポートでは、以下問題を解決しなくてはなりませんでした。
- データインポート時に外部キー制約が原因でエラーが発生するのを回避
発生事例
エラーが発生するケース
以下のコードは、並列処理を用いてCSVデータをインサートしていますが、外部キー制約のエラーが発生します。
1require 'csv'
2require 'parallel'
3
4table = "your_table" # インポート対象のテーブル名
5files = ["file-1.csv", "file-2.csv", "file-3.csv", "file-4.csv"] # CSVファイル名リスト
6
7# 外部キー制約を無効化
8TemporaryApplicationRecord.connection.execute("SET FOREIGN_KEY_CHECKS = 0")
9
10# テーブルをクリア
11TemporaryApplicationRecord.connection.execute("TRUNCATE TABLE #{table}")
12
13def import_csv(file, table)
14model = "Temporary::#{table.singularize.camelize}".constantize
15CSV.foreach(file, headers: true).each_slice(1000) do |rows|
16model.insert_all(rows.map { |row| row.to_h.transform_values { |v| v == "NULL" ? nil : v } })
17end
18end
19
20# 並列処理でCSVをインサート
21Parallel.each(files, in_processes: 4) do |file|
22import_csv(file, table)
23end
24
25# 外部キー制約を有効化
26TemporaryApplicationRecord.connection.execute("SET FOREIGN_KEY_CHECKS = 1”)
問題点
- SET FOREIGN_KEY_CHECKS = 0 を1度だけ設定しており、各プロセスで共有されていません。
エラーを防ぐコード
1以下のコードは、外部キー制約のエラーを回避するように修正されています。
2require 'csv'
3require 'parallel'
4
5table = "your_table"
6files = ["file-1.csv", "file-2.csv", "file-3.csv", "file-4.csv"]
7
8# テーブルをクリア
9TemporaryApplicationRecord.connection.execute("TRUNCATE TABLE #{table}")
10
11def import_csv(file, table)
12TemporaryApplicationRecord.connection.execute("SET FOREIGN_KEY_CHECKS = 0")
13model = "Temporary::#{table.singularize.camelize}".constantize
14CSV.foreach(file, headers: true).each_slice(1000) do |rows|
15model.insert_all(rows.map { |row| row.to_h.transform_values { |v| v == "NULL" ? nil : v } })
16end
17TemporaryApplicationRecord.connection.execute("SET FOREIGN_KEY_CHECKS = 1")
18end
19
20# 並列処理でCSVをインサート
21Parallel.each(files, in_processes: 4) do |file|
22import_csv(file, table)
23end
修正ポイント
プロセスごとに外部キー制約を設定
並列処理の中で、SET FOREIGN_KEY_CHECKS = 0 と SET FOREIGN_KEY_CHECKS = 1 を明示的に呼び出すことで、各プロセスが外部キー制約を無効化するように設定しました。
詳細解説
外部キー制約とは?
MySQLや他のデータベースでの外部キー制約は、データの整合性を確保するために使用されます。しかし、大量のデータを一括でインポートする場合、整合性チェックがボトルネックとなり、パフォーマンスに影響を与えることがあります。
SET FOREIGN_KEY_CHECKS = 0 を使用することで、外部キー制約のチェックを一時的に無効化することが可能です。ただし、これを正しく設定しないとエラーが発生することがあります。
なぜエラーが発生するのか?
並列処理を用いる場合、各プロセスは独立して実行されるため、1つのプロセスで無効化した外部キー制約が他のプロセスには適用されません。そのため、外部キー制約が有効な状態でデータがインサートされ、エラーが発生します。
修正コードの効果
修正版では、各プロセスで外部キー制約を明示的に無効化しているため、どのプロセスでも外部キー制約が原因のエラーが発生しません。
まとめ
大量データをインポートする際に外部キー制約のエラーを回避するには、以下のポイントを押さえることが大切です:
- 並列処理の中で外部キー制約の無効化を設定する。
この方法を適用することで、エラーを回避しながら大量データを効率的に処理できます。
ライトコードでは、エンジニアを積極採用中!
ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。
採用情報へ
プライベートの休日はインドアもアウトドアもどちらになることもあります。