InnoDBエンジンで挿入遅延を使用し、挿入ステートメントの接続を減らす方法は?


10

多くのデータベース書き込み、約70%の挿入、30%の読み取りを含むアプリケーションに取り組んでいます。この比率には、1回の読み取りと1回の書き込みと見なす更新も含まれます。insertステートメントを使用して、複数のクライアントが以下のinsertステートメントを介してデータベースにデータを挿入します。

$mysqli->prepare("INSERT INTO `track` (user, uniq_name, ad_name, ad_delay_time ) values (?, ?, ?, ?)");

問題は、insertステートメントがサーバーで最大 100%のCPU を使用するため、insert_delayまたはmysqli_multi_queryメカニズムのどちらを使用するかです。データベースでInnoDBエンジンを使用しているため、挿入の遅延は不可能です。サーバーへの挿入は〜36k /時間、99.89%の読み取りです。また、selectステートメントを使用して、単一のクエリデータを7回取得しています。このクエリの実行には、サーバーで150秒かかります。このタスクにはどのようなテクニックやメカニズムを使用できますか?サーバーのメモリは2 GBですが、メモリを拡張する必要がありますか?この問題を見てください、どんな提案も私に感謝します。

テーブルの構造:

+-----------------+--------------+------+-----+-------------------+----------------+
| Field           | Type         | Null | Key | Default           | Extra          |
+-----------------+--------------+------+-----+-------------------+----------------+
| id              | int(11)      | NO   | PRI | NULL              | auto_increment |
| user            | varchar(100) | NO   |     | NULL              |                |
| uniq_name       | varchar(200) | NO   |     | NULL              |                |
| ad_name         | varchar(200) | NO   |     | NULL              |                |
| ad_delay_time   | int(11)      | NO   |     | NULL              |                |
| track_time      | timestamp    | NO   | MUL | CURRENT_TIMESTAMP |                |
+-----------------+--------------+------+-----+-------------------+----------------+

私のデータベースの現在のステータスは、41kの挿入(書き込み)を示しています。これは、私のデータベースでは非常に低速です。

データベースのステータス


テーブルの定義を提供できますか?(すべての列、データ型およびインデックス)
ypercubeᵀᴹ

SHOW FULL PROCESSLISTCPUが100%使用されている場合の簡単なスニペットを教えてください。許可している接続の数と、この間に取得されている接続の数。
Derek Downey、

これらの2つのクエリを実行してください:SHOW GLOBAL VARIABLES LIKE 'innodb%';およびSELECT VERSION();とその出力を表示します。
RolandoMySQLDBA 2012年

実行している1秒あたりの挿入数を入力してください。
dabest1

コードがSQLインジェクションの影響を非常に受けやすい。準備されたステートメントとパラメーター化された値を使用します。
アーロンブラウン

回答:


11

書き込みより読み取りの方が多いため、以下をお勧めします

InnoDBの適切なチューニングが鍵となる

バッファープール(innodb_buffer_pool_sizeでサイズ設定

以来InnoDBはサポートされていないINSERT DELAYEDは大きなInnoDBのバッファプールを使用すると、INSERTに得ることができる最も近いものが遅れている使用して、。すべてのDML(INSERT、UPDATE、およびDELETE)はInnoDBバッファープールにキャッシュされます。書き込みのトランザクション情報は、すぐにREDOログ(ib_logfile0、ib_logfile1)に書き込まれます。バッファープールに送信された書き込みは、ibdata1(セカンダリインデックスのInsertBuffer、二重書き込みバッファー)を介してメモリからディスクに定期的にフラッシュされます。バッファープールが大きいほど、キャッシュできるINSERTの量が多くなります。RAMが8GB以上のシステムでは、RAMの75〜80%をinnodb_buffer_pool_sizeとして使用します。RAMが非常に少ないシステムでは、25%(OSに対応するため)。

警告:innodb_doublewriteを0に設定すると、書き込みをさらに高速化できますが、データの整合性のリスクがあります。また、innodb_flush_methodをO_DIRECTに設定して、InnoDBをOSにキャッシュしないようにすることで、速度を上げることもできます。

REDOログ(innodb_log_file_sizeでサイズ設定

デフォルトでは、REDOログの名前はib_logfile0およびib_logfile1で、それぞれ5MBになります。サイズはinnodb_buffer_pool_sizeの25%にする必要があります。REDOログがすでに存在する場合は、my.cnfに新しい設定を追加し、mysqlをシャットダウンして削除し、mysqlを再起動します。

ログバッファー(innodb_log_buffer_sizeでサイズ設定

ログバッファーは、変更をRAMに保持してからREDOログにフラッシュします。デフォルトは8Mです。ログバッファが大きいほど、ディスクI / Oは少なくなります。トランザクションが非常に大きい場合は、COMMITがミリ秒単位で遅くなる可能性があるので注意してください。

複数のCPUへのアクセス

MySQL 5.5およびMySQL 5.1 InnoDBプラグインには、InnoDBストレージエンジンが複数のCPUにアクセスするための設定があります。設定する必要があるオプションは次のとおりです。

  • innodb_thread_concurrencyは、InnoDBが開いたままにできる並行スレッドの数の上限を設定します。通常、(2 X CPU数)+ディスク数に設定することをお勧めします。昨年、私はPercona NYCカンファレンスから直接、それを0に設定して、実行している環境に最適なスレッド数を見つけるようにInnoDBストレージエンジンに警告する必要があることを学びました。
  • innodb_concurrency_ticketsは、無欠陥の同時実行性チェックをバイパスできるスレッドの数を設定します。この制限に達すると、スレッドの同時実行チェックが再び標準になります。
  • innodb_commit_concurrencyは、コミットできる同時トランザクションの数を設定します。デフォルトは0なので、これを設定しないと、任意の数のトランザクションを同時にコミットできます。
  • innodb_thread_sleep_delayは、InnoDBキューに再び入る前にInnoDBスレッドが休止できるミリ秒数を設定します。デフォルトは10000(10秒)です。
  • innodb_read_io_threads(これを3000に設定)およびinnodb_write_io_threads(これを7000に設定)(両方ともMySQL 5.1.38以降)は、指定された数のスレッドを読み取りと書き込みに割り当てます。デフォルトは4で、最大は64です。これらを64に設定します。また、innodb_io_capacityを10000に設定します。

MySQL 5.5にアップグレード

MySQL 5.0を使用している場合は、MySQL 5.5にアップグレードします。MySQL 5.1.37以前を使用している場合は、MySQL 5.5にアップグレードします。MySQL 5.1.38以降があり、MySQL 5.1のままにする場合は、InnoDBプラグインをインストールします。これにより、InnoDBのすべてのCPUを利用できます。


私のサーバーメモリは2GBなので、メモリによれば、innodbバッファープールを500Mに設定し、ログファイルを25%にプールし、ログバッファーも64Mに設定しました。しかし、それでもサーバーは非常にビジーです。メモリをアップグレードする必要がありますか?また、私のサーバーは32ビットUbuntuを使用しているため、最大メモリを4 GBに設定できます。
Shashank

サーバーがMySQL(apacheもPHPもなし)専用である場合、innodb_buffer_pool_sizeは2GBの75%になり、1536Mになります。4GBにアップグレードする場合、innodb_buffer_pool_sizeは3Gにすることができます。あなたが述べたように、ログファイルはバッファプールの25%でなければなりません。
RolandoMySQLDBA

サーバーはapache2、mysql、phpを実行していますが、この状況でメモリをアップグレードする必要がありますか、それともinnodbバッファープール以外に最適な解決策はありますか?
Shashank

この男はあなたに反対します:percona.com/blog/2008/11/21/…Percona と議論するのは難しいです。
Zenexer 2015年

Rolando-5.6と5.7のアップデートで回答に追加することをお勧めします。デフォルトが変更されました。他の設定が利用可能です。等多分PerconaとMariaDBと8.0のヒントが含まれています。
リックジェームズ

2

INT(2)は引き続き4バイトを使用します-おそらく、TINYINT UNSIGNEDを意味していましたか?

setnoにはいくつの異なる値がありますか?小さい場合、KEY(setno)は使用されません。INSERTはそのインデックスを更新する必要があります。KEYを削除すると、INSERTの速度が上がります。

CHAR(10)- flag常に10文字ですか?そしてutf8では?おそらく、フラグVARCHAR(10)CHARACTER SET asciiを使用できます。

挿入をバッチ処理します-一度に100は10倍の速度で実行されます。(100を超えると、「収益が減少します」。

自動コミットの価値は何ですか?各INSERTをBEGIN ... COMMITでラップしていますか?innodb_flush_log_at_trx_commitの値は何ですか?


:データが異なる値と異なるクライアントなどの外部ソースを経由して挿入された場合にどのように私はバッチ内のインサートを得るのですか....それは私が使用した場合に信頼性がありcode、挿入をt_nameに(COL1、COL2、COL3)の値(val1と、VAL2、val3は) (val1、val2、val3)、(val1、val2、val3)、(val1、val2、val3)、(val1、val2、val3); code
Shashank、2012年

1

キューを設定します。アプリケーションは一度に1行ずつキューに書き込み、最後に行を取り出して、最後の挿入から経過した時間数に基づいて、バッチでデータベースに挿入します。

一度に10,000個のインサートをバッチ処理するのが最も高速であるので、スイートスポットを見つけるためにテストする必要があります。

独自のシンプルなキューシステムを作成するか、既存のキューシステムを使用できます。次にいくつかの例を示します:HornetQおよびFile :: Queue。これは、他のいくつかの優れたオプションをリストしたSEへの投稿です:perl、php、pythonのメッセージキュー


私はこのアプローチに同意します。1つのアプリで5秒ごとに〜1500の挿入をバッチ処理していますが、それは1秒未満です。mysqlには、バッチ挿入を非常に迅速に実行させるメカニズムが内部に実装されているようです。
ドンウール
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.