3

MySQLサーバーでパフォーマンスをテストしており、2 億を超えるレコードでテーブルを埋めています。ストアド プロシージャは、大きな SQL 文字列の生成に非常に時間がかかります。ヘルプやコメントは大歓迎です。

システム情報:

  • データベース: MySQL 5.6.10 InnoDB データベース (テスト)。
  • プロセッサー: AMD Phenom II 1090T X6 コア、各コア 3910Mhz。
  • RAM: 16GB DDR3 1600Mhz CL8。
  • HD: SSD に Windows 7 64 ビット SP1、SSD に mySQL をインストール、機械式ハード ディスクにログを書き込みます。

ストアド プロシージャは、テーブルに挿入されるすべての値を使用して INSERT sql クエリを作成します。

DELIMITER $$
USE `test`$$

DROP PROCEDURE IF EXISTS `inputRowsNoRandom`$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `inputRowsNoRandom`(IN NumRows BIGINT)
BEGIN
    /* BUILD INSERT SENTENCE WITH A LOS OF ROWS TO INSERT */
    DECLARE i BIGINT;
    DECLARE nMax BIGINT;
    DECLARE squery LONGTEXT;
    DECLARE svalues LONGTEXT;

    SET i = 1;
    SET nMax = NumRows + 1;
    SET squery = 'INSERT INTO `entity_versionable` (fk_entity, str1, str2, bool1, double1, DATE) VALUES ';
    SET svalues = '("1", "a1", 100, 1, 500000, "2013-06-14 12:40:45"),';

    WHILE i < nMax DO
        SET squery = CONCAT(squery, svalues);
        SET i = i + 1;
    END WHILE;

    /*SELECT squery;*/
    SET squery = LEFT(squery, CHAR_LENGTH(squery) - 1);
    SET squery = CONCAT(squery, ";");
    SELECT squery;

    /* EXECUTE INSERT SENTENCE */
    /*START TRANSACTION;*/
    /*PREPARE stmt FROM squery;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
    */

    /*COMMIT;*/
END$$
DELIMITER ;


結果:

  1. 20000 個の文字列を連結すると、処理に約 45 秒かかります。

CALL test.inputRowsNoRandom(20000);

  1. 100000 個の文字列を連結するには、約 +5/12 分かかります O_O:

CALL test.inputRowsNoRandom(100000);

結果 (期間順) - 秒単位のステートメント期間 (合計) || フリーイングアイテム0.00005
50.00000
開始0.00002 20.00000の 実行
0.00001 10.00000の実行0.00001
10.00000
クリーンアップ0.00001 10.00000
合計0.00010100.00000

クエリ
変動値の実行によるステータス変数の変化Com_select 1 実行された SELECT ステートメントの 数 Questions 1 サーバーによって実行されたステートメントの数





テスト:
12 から 64 スレッドのさまざまな MySQL 構成で、キャッシュのオンとオフを設定し、ログを別のハードウェア ディスクに移動することを既にテストしました...
また、TEXT、INT を使用してテストしました..

追加情報:


質問:

  • コードに何か問題がありますか?最終的な SQL 文字列を作成するために 100000 個の文字列を送信すると、結果SELECT squery;は NULL 文字列になります。何が起こっていますか?(エラーがあるはずですが、表示されません)。
  • コードを改善して速度を上げることはできますか?
  • C/Java/PHP でファイルを生成して mysql に送信する必要がありますか?

    mysql -u mysqluser -p データベース名 < numbers.sql

  • MySQL は1つのSQLクエリに対して1 つのコアのみを使用いるようです。(私の単一のクエリは、約 150 のスレッドで合計 CPU の 20% しか使用していないため)。

アップデート:

4

2 に答える 2

6

特に RDBMS のその規模では、ループを使用しないでください。

クエリを使用して、テーブルに 100 万行をすばやく入力してみてください

INSERT INTO `entity_versionable` (fk_entity, str1, str2, bool1, double1, date)
SELECT 1, 'a1', 100, 1, 500000, '2013-06-14 12:40:45'
  FROM
(
select a.N + b.N * 10 + c.N * 100 + d.N * 1000 + e.N * 10000 + f.N * 100000 + 1 N
from (select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) a
      , (select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) b
      , (select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) c
      , (select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) d
      , (select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) e
      , (select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) f
) t

私の箱(MacBook Pro 16GB RAM、2.6Ghz Intel Core i7)では、完了するまでに約8秒かかりました

クエリ OK、1000000 行が影響を受ける (7.63 秒)
レコード: 1000000 重複: 0 警告: 0

UPDATE1準備済みステートメントを使用するストアド プロシージャのバージョン

DELIMITER $$
CREATE PROCEDURE `inputRowsNoRandom`(IN NumRows INT)
BEGIN
    DECLARE i INT DEFAULT 0;

    PREPARE stmt 
       FROM 'INSERT INTO `entity_versionable` (fk_entity, str1, str2, bool1, double1, date)
             VALUES(?, ?, ?, ?, ?, ?)';
    SET @v1 = 1, @v2 = 'a1', @v3 = 100, @v4 = 1, @v5 = 500000, @v6 = '2013-06-14 12:40:45';

    WHILE i < NumRows DO
        EXECUTE stmt USING @v1, @v2, @v3, @v4, @v5, @v6;
        SET i = i + 1;
    END WHILE;

    DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;

約 3 分で完了:

mysql> CALL inputRowsNoRandom(1000000);
クエリ OK、影響を受ける行は 0 (2 分 51.57 秒)

8 秒と 3 分の違いを感じてください

UPDATE2 処理を高速化するために、明示的にトランザクションを使用し、挿入をバッチでコミットできます。というわけで、SPの改良版です。

DELIMITER $$
CREATE PROCEDURE inputRowsNoRandom1(IN NumRows BIGINT, IN BatchSize INT)
BEGIN
    DECLARE i INT DEFAULT 0;

    PREPARE stmt 
       FROM 'INSERT INTO `entity_versionable` (fk_entity, str1, str2, bool1, double1, date)
             VALUES(?, ?, ?, ?, ?, ?)';
    SET @v1 = 1, @v2 = 'a1', @v3 = 100, @v4 = 1, @v5 = 500000, @v6 = '2013-06-14 12:40:45';

    START TRANSACTION;
    WHILE i < NumRows DO
        EXECUTE stmt USING @v1, @v2, @v3, @v4, @v5, @v6;
        SET i = i + 1;
        IF i % BatchSize = 0 THEN 
            COMMIT;
            START TRANSACTION;
        END IF;
    END WHILE;
    COMMIT;
    DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;

異なるバッチ サイズでの結果:

mysql> CALL inputRowsNoRandom1(1000000,1000);
クエリ OK、影響を受ける行は 0 (27.25 秒)

mysql> CALL inputRowsNoRandom1(1000000,10000);
クエリ OK、影響を受ける行は 0 (26.76 秒)

mysql> CALL inputRowsNoRandom1(1000000,100000);
クエリ OK、影響を受ける行は 0 (26.43 秒)

違いは自分でわかります。それでも、クロス結合よりも 3 倍以上悪いです。

于 2013-06-17T02:44:27.103 に答える