Edited at

SQLのインサートとバルクインサート


インサート

1件のみデータをインサートする場合、下記のようなクエリになります。

INSERT INTO user(name) values('test1');

この書き方で複数インサートするには、複数回インサート文を記述すればできます。

INSERT INTO user(name) values('test1');

INSERT INTO user(name) values('test2');
INSERT INTO user(name) values('test3');


バルクインサート

複数行のデータをインサートする際、1回のsql文でインサートしたいって時に使えます。

バルクインサートでは1回のトランザクションでインサートすることができるため、

トランザクションを発行して何回もインサート処理をループさせるよりもコンテキストスイッチの回数が減るため実行速度が速いです。

INSERT INTO user values('test4'), ('test5'), ('test6');


コンテキストスイッチ

wikiによると、コンテキストスイッチとは

複数のプロセスが1つのCPUを共有できるように、CPUの状態(コンテキスト)を保存したり復元したりする過程のことである

実行中のプロセスから他のプロセスを実行するため、プロセスの切り替えを行うときにコンテキストスイッチが発生する。


プログラムを書くときに意識をした方が良い

細かい文法などはわからなくて良いのですが、下記のようなプログラムをかくと $users が100件あれば100回のインサート、1000件あれば1000件のインサートが行われます。

foreach ($users as $user) {

// 1件ずつuserを作成してインサートをしている
Users::create([
'name' => $user->name,
'hoge' => $user->hoge
]);
}

上記のコードを下記のように変更すれば、foreachの計算量は変わりませんが、インサートは1回ですみます。

$data = [];

// まとめてインサートをするデータを先に作成している
foreach ($users as $user) {
$data[] = [
'name' => $user->name,
'hoge' => $user->hoge
];
}

// インサートは1回でOK
DB::table('users')->insert($data);

基本的に1件ずつ処理をしないといけない理由がない場合には、まとめてできないかを考えると良いと思います。


計算量を意識する

下記の記事が参考になります。

開発新卒に捧ぐ、基本のアルゴリズムと計算量


csvファイルのデータをインポートする

例えばcsvファイルのデータをすべてデータベースのテーブルにインポートする際にもバルクインサートを使用することができる。

BULK INSERT テーブル名

FROM 'ファイルのパス'
WITH (FIELDTERMINATOR = '区切り文字',
ROWTERMINATOR = '改行文字列'
);


ちなみに

csvファイルのデータをインポートする方法として、バルクインサートの他にbcp(bulk copy program)というコマンドが存在する。

bcpではSQLServerのテーブルにインポートしたり、データをテーブルからデータファイルにエクスポートしたりすることができる。

あとバルクアップデートもありますので、まとめてできそうなのに1件ずつ処理をしていることがあれば検索してみてください。