CodeGym /コース /SQL SELF /データ大量インポートの最適化

データ大量インポートの最適化

SQL SELF
レベル 24 , レッスン 3
使用可能

例えば、100万行のデータをインポートしなきゃいけないと想像してみて。もし遅い方法でやったら、サーバーがずっと忙しくなっちゃうし、ユーザーもDBのレスポンスが遅くなってイライラするかも。しかも最悪なのは、コーヒーが冷めるまで終わらないこと!最適化すればサーバーの負荷を減らして、待ち時間も短縮できるし、インポート中のエラーも減らせるんだ。

まずはシンプルな手順から始めて、だんだんテクニカルなテクニックも紹介していくね。

インデックスとトリガーの無効化

インデックスやトリガーって、DBを賢くしてくれる便利な機能だよね。でも大量データをインポートする時は、1行ごとにインデックス更新やトリガー実行が走るから、めっちゃ遅くなることがあるんだ。

だから一時的にそれらをオフにしちゃおう。

インデックスとトリガーを無効化する例:

-- テーブルのトリガーを無効化
ALTER TABLE students DISABLE TRIGGER ALL;

-- データをインポート
COPY students FROM '/path/to/students.csv' DELIMITER ',' CSV HEADER;

-- トリガーを再度有効化
ALTER TABLE students ENABLE TRIGGER ALL;

どう動くの?

  1. DISABLE TRIGGER ALLで一時的に全トリガーをオフにする。
  2. インポート後、ENABLE TRIGGER ALLでトリガーを元に戻す。

よくあるミス: トリガーを戻し忘れると、自動更新とかの仕組みが動かなくなることがあるよ。必ず元に戻してね。スマホの「機内モード」を解除し忘れるのと同じ感じ!

トランザクションの利用

トランザクションを使うと、全部のデータを一つの大きな操作としてインポートできる。もし途中で何か失敗しても、ロールバックできるから、DBが中途半端な状態にならないよ。

トランザクション利用の例:

-- トランザクション開始
BEGIN;

-- データをインポート
COPY courses FROM '/path/to/courses.csv' DELIMITER ',' CSV HEADER;

-- 変更を確定
COMMIT;

なんで速くなるの?

トランザクションなしだと、1行ごとにサーバーが変更を確定するけど、トランザクションを使えば最後に1回だけ確定するから、めっちゃ時間を節約できるよ。

整合性チェックの無効化

インポート中に外部キーや一意制約のチェックが不要なら、オフにしよう。そうしないと、DBが毎行チェックして遅くなる。

整合性チェックを無効化する例:

SET session_replication_role = 'replica';

-- データをインポート
COPY enrollments FROM '/path/to/enrollments.csv' DELIMITER ',' CSV HEADER;

SET session_replication_role = 'origin';

session_replication_role = 'replica'は、データの整合性チェック(例えば一意性やFOREIGN KEY制約)をオフにするよ。

実行用メモリの増加

PostgreSQLのメモリ設定を調整すると、インポートのパフォーマンスが上がることがある。ポイントはwork_memmaintenance_work_memだよ。

メモリ増加の例:

-- メモリを増やす
SET work_mem = '64MB';
SET maintenance_work_mem = '256MB';

-- データをインポート
COPY teachers FROM '/path/to/teachers.csv' DELIMITER ',' CSV HEADER;

どう役立つの?

  • work_memはソートやハッシュなどの中間処理用。
  • maintenance_work_memはインデックス再構築などの操作に影響する。

アドバイス: メモリ増やしすぎると、リソースが足りなくなることもあるから注意してね。

インポート前のデータ準備

データを事前に準備しておくと、インポート時間を大幅に短縮できる。例えば重複行があれば、先にフィルタリングしておけば、PostgreSQLが無駄な処理をしなくて済むよ。

データクリーンアップの例:

重複行があるファイルなら、Pythonで削除できるよ。

import pandas as pd

# CSVファイルを読み込む
data = pd.read_csv('students.csv')

# 重複を削除
data = data.drop_duplicates()

# クリーンなCSVを保存
data.to_csv('students_clean.csv', index=False)

データのパーティショニング

巨大なファイルなら、いくつかの小さいファイルに分割しよう。その方がPostgreSQLが効率よく処理できるよ。

例:

large_data.csvをLinuxで1000行ごとに分割:

split -l 1000 large_data.csv chunk_

その後、個別にインポート:

COPY students FROM 'chunk_aa' DELIMITER ',' CSV HEADER;
COPY students FROM 'chunk_ab' DELIMITER ',' CSV HEADER;
-- などなど

バックグラウンドでのインポート実行

もしできるなら、バックグラウンドプロセスでデータをインポートして、メインDBの負荷を減らそう。

pg_cronみたいなツールを使えば、スケジュール実行もできるよ。

例:pg_cronでバックグラウンドインポートを設定:

CREATE EXTENSION pg_cron;

SELECT cron.schedule('*/5 * * * *', $$COPY students FROM '/path/to/data.csv' DELIMITER ',' CSV HEADER$$);

5分ごとにファイルからテーブルにデータがインポートされるよ。

これはあくまで例だから、実際にはこうしない方がいいかも!でもPostgreSQLはめっちゃ柔軟で、SQLスクリプトからでも色々できるってことを知ってほしかったんだ。

落とし穴

気をつけたいポイント:

  • インデックスやトリガーをオフにしたら、必ず元に戻してね!忘れると後でトラブルになるよ。
  • メモリ設定を上げすぎると、サーバーのリソースが足りなくなることも。1つの欲張りなクエリでRAMが全部なくなるかも。
  • トランザクションを使う時は、データファイルに致命的なエラーがないか確認してね。1つでもエラーがあると全部ロールバックされちゃう。

今後のおすすめ

これで大量データのインポート最適化方法がわかったね。インデックスの無効化からトランザクションの活用まで、これらのスキルがあれば、速くインポートできるし、サーバーリソースも節約できるし、イライラも減るし、コーヒーも冷めないし、ユーザーもハッピー!

次にギガバイト級のファイルを扱う時も、もう怖くないよ!

コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION