2016-10-07 3 views
1

現在、私はTokuDBをテストしており、とても感心しています。現時点では、1秒あたりのインサート数は、2つの同時実行ジョブを実行して1秒間に50,000を超えてピークに達しています。平均インサート速度は1秒あたり38.000〜42.000インサートです。tokudbで50.000以上の挿入を行うにはどうすればいいですか?

私は、今のところ12億の計算された行を挿入し、近い将来には約60億を挿入する必要があるので、さらに高い100.000インサート/秒を実行したいと思います。

  1. ハードウェア:4GBのRAMを持つVPS、150ギガバイトSSD、2つのコア:インテルのWestmere E56xx/L56xx/X56xx(Nehalemの私はこの:-)

    私の現在の設定を達成する方法についていくつかのアドバイスをしたいと思います-C)2.59GHzのCPU

  2. ディスクのマウントオプション:デフォルト、noatimeオプション
  3. OS:CentOSの6.8 64ビット
  4. データベース:Perconaサーバー5.7.14-8

のmy.cnfの設定:

# TokuDB # 
tokudb_cache_size = 2G 
tokudb_commit_sync = 0 
tokudb_fsync_log_period = 1000 

TokuDBテーブルのレイアウト:

CREATE TABLE `t1` (
    `id` int(15) NOT NULL AUTO_INCREMENT, 
    `m_id` int(11) NOT NULL, 
    `c1` decimal(6,2) DEFAULT NULL, 
    `c2` decimal(6,2) DEFAULT NULL, 
    `c3` decimal(6,2) DEFAULT NULL, 
    `c4` decimal(6,2) DEFAULT NULL, 
    `c5` decimal(6,2) DEFAULT NULL, 
    `c6` decimal(6,2) DEFAULT NULL, 
    `c7` decimal(6,2) DEFAULT NULL, 
    `factor` decimal(4,2) DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=TokuDB DEFAULT CHARSET=latin1 

CREATE TABLE `t2` (
    `id` int(15) NOT NULL AUTO_INCREMENT, 
    `v_id` int(15) NOT NULL, 
    `pid` int(11) DEFAULT NULL, 
    `amount` decimal(6,2) DEFAULT NULL, 
    `unit` int(1) DEFAULT '0', 
    PRIMARY KEY (`id`) 
) ENGINE=TokuDB DEFAULT CHARSET=latin1 

私は、他のすべてのインデックス 主キー索引を使用していないという事実を認識してね。これは、鍵が の挿入時に負の時間の影響があるためです。各テーブルのクラスタキーは、挿入ジョブの末尾の に作成されます。

追加MySQLのコマンドラインオプション:

SET unique_checks=OFF; 

誰かが、これは非常に高く評価されるだろうか、その後を知っているだろう場合はどういうわけか、私は=現在UNIQUE_CHECKS(.. my.cnfの中でこれを取得することはできませんよmy.cnfの変数が分からないためにMySQLが起動しないようにします)。

SQLステートメントは、15.000のバッチでグループ化されています。 PHPスクリプトは、SQL文を生成し、MySQLサーバにmysqli_multiqueryを経由して、クエリを送信します:SQLのINSERT文の

<?PHP   
    foreach (generateCombinations($Arr) as $c) { 

      $QueryBatch[] = "insert into t1 values (NULL" 
          . ", " . $record->id 
          . ", " . rand(1, 35) 
          . ", " . rand(1, 140) 
          . ", " . rand(1, 20) 
          . ", NULL" 
          . ", " . rand(1, 14) 
          . ", " . rand(1, 300) 
          . ", " . rand(1, 4) 
          . ", NULL);"; 
      $QueryBatch[] = "SET @t1id = LAST_INSERT_ID();"; 

      $cntBatch++; 

      $pquery = array(); 
      foreach ($c as $key => $pid){ 

        if (is_null($pid)) 
          continue; 

        $pquery[] = "(NULL, @t1id, " . $pid . ", " . rand(1, 800) . ", 0)"; 

        $cntBatch++; 
      } 

      $QueryBatch[] = "insert into t2 values " . implode(',', $pquery) . ";"; 

      if ($cntBatch > 15000) { 

        $query = implode($QueryBatch); 

        if ($mysqli->multi_query($query)){ 
          while ($mysqli->next_result()) {;} 
        } else { 
          printf("Errormessage: %s\n", $mysqli->error); 
          echo $query . "\n"; 
        } 

        $cntBatch = 0; 
        unset($QueryBatch); 
      } 

    } 
?> 

例:それは私だったら

insert into t1 values (NULL, 1 , 30, 100, 15, NULL, 10, 250, 2, NULL); 
SET @t1id = LAST_INSERT_ID(); 
insert into t2 values (NULL, @t1id, 1, 750, 0),(NULL, @t1id, 1, 600, 0),(NULL, @t1id, 1, 500, 0),(NULL, @t1id, 1, 400, 0),(NULL, @t1id, 1, 300, 0),(NULL, @t1id, 1, 200, 0),(NULL, @t1id, 1, 100, 0); 
insert into t1 values (NULL, 2 , 25, 95, 14, NULL, 11, 200, 3, NULL); 
SET @t1id = LAST_INSERT_ID(); 
insert into t2 values (NULL, @t1id, 1, 600, 0),(NULL, @t1id, 1, 100, 0),(NULL, @t1id, 1, 300, 0),(NULL, @t1id, 1, 443, 0),(NULL, @t1id, 1, 521, 0),(NULL, @t1id, 1, 213, 0),(NULL, @t1id, 1, 433, 0); 
[.. At least 14982 more..] 

答えて

2

が、私は数を削減う文が実行され、コミット数が削減されます。私は、BEGIN TRANSACTIONまたはCOMMITステートメントが表示されないので、AUTO_COMMITが有効であると仮定しています。

これは、個別のINSERTSETステートメントの全体的な断片です。少なくとも、子テーブルへの挿入は、複数の行挿入を使用しており、各行に対して別々の挿入文を使用しているわけではありません。

私はこれが高速であるために必要な場合、私は

  1. t1テーブルのid値を生成し、INSERT文
  2. のものがLAST_INSERT_ID()
  3. 使用への呼び出しを廃止含まれるであろうt1の複数行の挿入(行ごとに別々のINSERT文ではなく)
  4. 使用BEGIN TRANSACTIONおよびCOMMIT
  5. は、InnoDBのためだったら、私もSET FOREIGN_KEY_CHECKS=0にしてくださいロック

のための潜在的な競合を避けるために(シリアライズ)t1への挿入を実行するために単一プロセスを実行します。

コード内にはすでにrand関数の呼び出しがあります。整数をt1に増やしても、針は動かないでしょう。開始時に、現在のAUTO_INCREMENT値を取得するか、MAX(ID)のどちらかを取得するクエリが必要です。

基本的には、実行されている文の数を減らし、各明細書によって行われた作業、および各作業の前には、それぞれCOMMIT

文当たり10(t1)行を挿入すると、が大幅に実行する必要があるステートメントの数を減らします。

BEGIN TRANSACTION; 
-- insert ten rows into t1 
INSERT INTO t1 (id,m_id,c1,c2,c3,c4,c5,c6,c7,factor) VALUES 
(444055501, 1 , 30, 100, 15, NULL, 10, 250, 2, NULL) 
,(444055502, 2 , 25, 95, 14, NULL, 11, 200, 3, NULL) 
, ... 
,(444055510, 10 , 7, 45, 12, NULL, 10, 300, 4, NULL) 
; 
-- batch together the t2 rows associated with the ten t1 rows we just inserted 
INSERT INTO t2 VALUES 
-- 444055501 
(NULL, 444055501, 1, 750, 0) 
,(NULL, 444055501, 1, 600, 0) 
,(NULL, 444055501, 1, 500, 0) 
,(NULL, 444055501, 1, 400, 0) 
,(NULL, 444055501, 1, 300, 0) 
,(NULL, 444055501, 1, 200, 0) 
,(NULL, 444055501, 1, 100, 0) 
-- 444055502 
,(NULL, 444055502, 1, 600, 0) 
,(NULL, 444055502, 1, 100, 0) 
,(NULL, 444055502, 1, 300, 0) 
,(NULL, 444055502, 1, 443, 0) 
,(NULL, 444055502, 1, 521, 0) 
,(NULL, 444055502, 1, 213, 0) 
,(NULL, 444055502, 1, 433, 0) 
-- 444055503 
, ... 
; 

-- another ten rows into t1 
INSERT INTO t1 (id,m_id,c1,c2,c3,c4,c5,c6,c7,factor) VALUES 
(444055511, 11 , 27, 94, 15, NULL, 10, 250, 11, NULL) 
,(444055512, 12 , 24, 93, 14, NULL, 11, 200, 12, NULL) 
, ... 
,(444055520, 10 , 7, 45, 12, NULL, 10, 300, 4, NULL) 
; 
INSERT INTO t2 VALUES 
(NULL, 444055511, 1, 820, 0) 
,(NULL, 444055511, 1, 480, 0) 
, ... 
; 

-- repeat INSERTs into t1 and t2, and after 1000 loops 
-- i.e. 10,000 t1 rows, do a commit 
COMMIT; 
BEGIN TRANSACTION; 
INSERT INTO t1 ... 

LOADデータINFILE

インサートの性能のいかなる議論は、少なくともLOAD DATA INFILEに言及せず不完全であろう。

最高のパフォーマンスを得るには、それを上回ることはできません。しかし、ファイルにデータがなく、キー値(t2に外部キーが必要で、データを生成するためにrandへのすべての呼び出しがあります)がないため、LOAD DATA INFILEは見えません

+0

スペンサー7593、あなたの詳細な答えをありがとう!私はあなたが言っていることを理解していることを理解していますが、事柄です;関連するt2の対応するレコードのt1のIDを知る必要があります。基本的に1つのジョブだけがレコードを作成するので、自動インクリメントを削除してIDを作成することをお勧めします – Robbert

+1

AUTO_INCREMENTカラムに値を指定することができますAUTO_INCREMENTを削除したり無効にしたりすることなく、NULL値を指定してAUTO_INCREMENTの動作を取得します。 'id'値を評価し、両方の値に' t1'と 't2'の両方にその値を与えてください。これをスピードアップするために私がやることは... SQL文の数とCOMMITの数を減らすことです。 – spencer7593

+0

InnoDBでは、auto_incrementの動作を設定して*連続* auto_increment値を取得します。したがって、複数行の挿入は、最初の行がLAST_INSERT_ID()+ 0であり、2行目がLAST_INSERT_ID()+ 1までLAST_INSERT_ID()+ ROW_COUNT()まで挿入されていることがわかります。AUTO_INCREMENT値を使用しなければならない場合は、挿入を 't1'(mutli-row insert)、' SELECT LAST_INSERT_ID()INTO @ lid'にバッチし、次に 't2'への挿入は' @ lid + 0 '挿入された第1のt1行に関する行については' @ lid + 1 'が挿入される。 (私の注意は、tokudbのAUTO_INCREMENTの動作がInnoDBと同じであるかどうか分かりません) – spencer7593

関連する問題