
A 回答 (4件)
- 最新から表示
- 回答順に表示
No.4
- 回答日時:
補足、プロシージャを使って10のn乗件単位でやるならこうかな
(思ったより速くなったけど、まだ改善の余地あり)
一度バルクSQLをつくってから流し込むので
あまり長すぎるSQLを書くとオーバーフローする可能性があります。
要素数やレコード長によりますが1000件単位くらいが妥当かなと
DROP PROCEDURE IF EXISTS MYPROCEDURE4;
DELIMITER //
CREATE PROCEDURE MYPROCEDURE4()
BEGIN
DECLARE a BLOB;
DECLARE done INT DEFAULT 0;
DECLARE CUR CURSOR FOR
SELECT
CONCAT('INSERT IGNORE INTO `tbl2` VALUES('
,GROUP_CONCAT('\'',id,'\',\'',data,'\',\'',val,'\'' separator '),(')
,')') as x
FROM `tbl1`
GROUP BY TRUNCATE(id,-2);/* PER1=0, PER10=-1, PER100=-2, PER1000=-3*/
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
SET group_concat_max_len = 10000000;
OPEN CUR;
REPEAT
FETCH CUR INTO a;
IF NOT done THEN
SET @sql=a;
PREPARE stmt from @sql;
EXECUTE stmt;
END IF;
UNTIL done END REPEAT;
CLOSE CUR;
END
//
DELIMITER ;
TRUNCATE `tbl2`;
CALL MYPROCEDURE4;
No.3
- 回答日時:
試しにプロシージャをつかってテストをしてみました
パターンは3つ
(1)1レコードごとに投入を繰り返す
(2)複数レコードをまとめて投入を繰り返す
(3)INSERT ・・・ SELECT で投入する
質問者さんは(3)は遅いとのことでしたが
実際やってみたところ早い順 (3)>(1)>(2)でした
実際圧倒的に(3)が速いようなので、プロシージャではあきらめて#2で提案したように
mysqldumpなどで処理する方がよいかもしれませんね。
(プロシージャだとCONCATで同じデータをくりかえし処理するので無駄がおおい?)
テスト
CREATE TABLE `tbl1`(`id` INT NOT NULL UNIQUE,`data` VARCHAR(100),`val` DOUBLE);
CREATE TABLE `tbl2`(`id` INT NOT NULL UNIQUE,`data` VARCHAR(100),`val` DOUBLE);
※1000データをつくる
DROP PROCEDURE IF EXISTS MYPROCEDURE1;
DELIMITER //
CREATE PROCEDURE MYPROCEDURE1()
BEGIN
DECLARE i INT DEFAULT 0;
WHILE i<1000 DO
INSERT IGNORE INTO tbl1 VALUES(i,'x',RAND());
SET i=i+1;
END WHILE;
END
//
DELIMITER ;
TRUNCATE `tbl2`;
CALL MYPROCEDURE1;
(1)1レコード毎投入:平均して1秒前後
DROP PROCEDURE IF EXISTS MYPROCEDURE2;
DELIMITER //
CREATE PROCEDURE MYPROCEDURE2()
BEGIN
DECLARE a INT;
DECLARE b VARCHAR(100);
DECLARE c DOUBLE;
DECLARE done INT DEFAULT 0;
DECLARE CUR CURSOR FOR
SELECT id,data,val FROM tbl1;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
OPEN CUR;
REPEAT
FETCH CUR INTO a,b,c;
SET @sql='INSERT IGNORE INTO `tbl2` VALUES ';
SET @sql=CONCAT(@sql,'(\'',a,'\',\'',b,'\',\'',c,'\')');
PREPARE stmt from @sql;
EXECUTE stmt;
UNTIL done END REPEAT;
CLOSE CUR;
END
//
DELIMITER ;
TRUNCATE `tbl2`;
CALL MYPROCEDURE2;
(2)100レコードをまとめて投入を繰り返す:平均して1.4秒くらい
DROP PROCEDURE IF EXISTS MYPROCEDURE3;
DELIMITER //
CREATE PROCEDURE MYPROCEDURE3()
BEGIN
DECLARE a INT;
DECLARE b VARCHAR(100);
DECLARE c DOUBLE;
DECLARE count INT DEFAULT 0;
DECLARE done INT DEFAULT 0;
DECLARE CUR CURSOR FOR
SELECT id,data,val FROM tbl1;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
OPEN CUR;
REPEAT
FETCH CUR INTO a,b,c;
IF count>100 THEN
SET count=0;
END IF;
IF count=0 THEN
SET @sql='INSERT IGNORE INTO `tbl2` VALUES ';
ELSE
SET @sql=CONCAT(@sql,',');
END IF;
SET @sql=CONCAT(@sql,'(\'',a,'\',\'',b,'\',\'',c,'\')');
PREPARE stmt from @sql;
EXECUTE stmt;
SET count=count+1;
UNTIL done END REPEAT;
CLOSE CUR;
END
//
DELIMITER ;
CALL MYPROCEDURE3;
(3)INSERT ・・・ SELECT で投入:平均0.01秒くらい
TRUNCATE `tbl2`;
INSERT tbl2 SELECT * FROM tbl1;
No.1
- 回答日時:
>プロシージャを作成してselectした結果で
>バルクinsertをしようと思うのですが
その通りやればいいのでは?
ちなみに100万件のデータをどうやって取ってくるつもりか
書いていないので、書きようがないのですが
たぶん1発でやるといろいろオーバーフローしそうなので、
1万件ずつくらいで分割しながらやるとよいです
INSERT INTO テーブル VALUESに対して(?,?,・・・・)という受け皿をつくって
$stmt = $pdo->prepare( $query);
$stmt->execute($data);
のようにすればよいでしょう。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
教えて!gooグレードポイントがdポイントに変わります!
dアカウント連携を行っていただくと、グレードに応じて「dポイント」が進呈されるようになります。
-
insertを高速化させたい
その他(データベース)
-
SQLServer Insertが遅い
SQL Server
-
数百万件レコードのdelete
SQL Server
-
4
oracleのinsert select性能
Oracle
-
5
トランザクションログを出力せずにデータを削除する方法
Oracle
-
6
MS SQLServer のSQLで文字列の前にN:
その他(データベース)
-
7
CSVファイルをBULK INSERTでSQLserverに読み込むことは可能?
その他(データベース)
-
8
GROUP BYを行った後に結合したい。
Oracle
-
9
[性能改善]AccessのDBに大量のデータをUpdateする場合の性能対策について
その他(データベース)
-
10
含まない言い方ってどうしたらいいんでしょうか
日本語
-
11
各伝票に対して明細を1行目だけ表示したい
SQL Server
-
12
PRIMARY KEYのコピー
MySQL
-
13
テーブルの最後(最新)のレコードを抽出したい
MySQL
-
14
SELECT 文 GROUP での1件目を取得
SQL Server
-
15
ROWNUMについて
Oracle
-
16
2つのテーブルから条件に一致しないデータ抽出
SQL Server
-
17
復旧中のデータベースについて
SQL Server
-
18
PostgreSQLのパフォーマンスについて質問です。
PostgreSQL
-
19
テーブルのヘッダとボディの幅がズレルのを防ぐ
HTML・CSS
-
20
同じSQL文で極端に検索が遅くなる時がある
MySQL
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
人気Q&Aランキング
-
4
「Duplicate entry '1' for key...
-
5
SQLサーバから、項目の属性(型...
-
6
php mysqlを使用してのリーグ表...
-
7
PL/SQLの変数について
-
8
複数JOINしているとCOUNTが正し...
-
9
MYSQLでSQLSERVERのリンクサー...
-
10
マイクラPC版のコマンドで効率...
-
11
複数テーブルのGROUP BY の使い...
-
12
入力値と外部キーをINSERTするには
-
13
【初心者】特定の文字に色をつ...
-
14
AUTO_INCREMENT を複数のテーブ...
-
15
inner joinをすると数がおかし...
-
16
”photo id” とは何ぞや?
-
17
DB設計について
-
18
SELECT文で片方のテーブルを優...
-
19
バインド変数について
-
20
SQL Left Join で重複を排除す...
おすすめ情報
公式facebook
公式twitter
回答ありがとうございます。
プロシージャ内で、大量データをselectして
数件ずつバルクinsertしたいのですがどう書いていいかわからず・・・。
もしくは、大量にselectした結果を高速にinsertできる別の方法があれば
教えていただきたいです・・・。