web-dev-qa-db-ja.com

挿入クエリが完了するまでに時間がかかることがあるのはなぜですか?

これはかなり単純な問題です。テーブルへのデータの挿入は、挿入クエリに数秒かかる場合を除いて、通常は正常に機能します。 (私はではなくデータを一括挿入しようとしています。)挿入クエリのシミュレーションが2を超えることがある理由を見つけるために、シミュレーションをセットアップしました。実行する秒。 Joshuaさんは、インデックスファイルを調整している可能性があると提案しました。 id(主キーフィールド)を削除しましたが、それでも遅延が発生します。

MyISAMテーブルがあります:daniel_test_insert(このテーブルは完全に始まります空):

create table if not exists daniel_test_insert ( 
    id int unsigned auto_increment not null, 
    value_str varchar(255) not null default '', 
    value_int int unsigned default 0 not null, 
    primary key (id) 
)

データを挿入しますが、挿入クエリの実行に2秒以上かかる場合があります。 このテーブルには読み取りはありません-シングルスレッドプログラムによるシリアル書き込みのみ。

まったく同じクエリを100,000回実行して、クエリに時々時間がかかる理由を見つけました。これまでのところ、それはランダムに発生しているようです。

たとえば、このクエリは4.194秒かかりました(挿入に非常に長い時間がかかります)。

Query: INSERT INTO daniel_test_insert SET value_int=12345, value_str='afjdaldjsf aljsdfl ajsdfljadfjalsdj fajd as f' - ran for 4.194 seconds
status               | duration | cpu_user  | cpu_system | context_voluntary | context_involuntary | page_faults_minor
starting             | 0.000042 | 0.000000  | 0.000000   | 0                 | 0                   | 0                
checking permissions | 0.000024 | 0.000000  | 0.000000   | 0                 | 0                   | 0                
Opening tables       | 0.000024 | 0.001000  | 0.000000   | 0                 | 0                   | 0                
System lock          | 0.000022 | 0.000000  | 0.000000   | 0                 | 0                   | 0                
Table lock           | 0.000020 | 0.000000  | 0.000000   | 0                 | 0                   | 0                
init                 | 0.000029 | 0.000000  | 0.000000   | 1                 | 0                   | 0                
update               | 4.067331 | 12.151152 | 5.298194   | 204894            | 18806               | 477995           
end                  | 0.000094 | 0.000000  | 0.000000   | 8                 | 0                   | 0                
query end            | 0.000033 | 0.000000  | 0.000000   | 1                 | 0                   | 0                
freeing items        | 0.000030 | 0.000000  | 0.000000   | 1                 | 0                   | 0                
closing tables       | 0.125736 | 0.278958  | 0.072989   | 4294              | 604                 | 2301             
logging slow query   | 0.000099 | 0.000000  | 0.000000   | 1                 | 0                   | 0                
logging slow query   | 0.000102 | 0.000000  | 0.000000   | 7                 | 0                   | 0                
cleaning up          | 0.000035 | 0.000000  | 0.000000   | 7                 | 0                   | 0

(これはSHOW PROFILEコマンドの省略バージョンです。すべてゼロの列を破棄しました。)

今回の更新では、信じられないほど多くのコンテキストスイッチとマイナーページフォールトが発生します。 Opened_Tablesは、このデータベースで10秒ごとに約1増加します(table_cacheスペースが不足していません)

統計:

  • MySQL 5.0.89

  • ハードウェア:32ギガのRAM/8コア@ 2.66 GHz; RAID 10 SCSIハードディスク(SCSI II ???)

  • ハードドライブとRAIDコントローラにクエリを実行しました。エラーは報告されていません。 CPUは約50%アイドルです。

  • iostat -x 5(ハードディスクの使用率が10%未満と報告)トップレポートの平均負荷は1分間で約10(dbマシンでは通常)

  • スワップスペースには156kが使用されています(32 GBのRAM)

このパフォーマンスの遅れの原因を突き止めるのに困っています。これは、低負荷スレーブでは発生せず、高負荷マスターでのみ発生します。これは、メモリテーブルとinnodbテーブルでも発生します。誰か提案はありますか? (これはプロダクションシステムなので、エキゾチックなものはありません!)

33
Daniel

私のシステムでも同じ現象に気づきました。通常1ミリ秒かかるクエリは、突然1〜2秒かかります。私の場合はすべて、単純な単一テーブルのINSERT/UPDATE/REPLACEステートメントです---どのSELECTにもありません。ロード、ロック、またはスレッドの構築は明らかではありません。

これはダーティページのクリア、ディスクへの変更のフラッシュ、またはいくつかの隠されたミューテックスが原因であると思っていましたが、まだ絞り込んでいません。

また除外

  • サーバーの負荷-高負荷との相関なし
  • エンジン-InnoDB/MyISAM/Memoryで発生します
  • MySQLクエリキャッシュ-オンでもオフでも発生します
  • ログローテーション-イベントに相関関係はありません

この時点で私が持っている他の唯一の観察は、複数のマシンで同じdbを実行しているという事実から派生しています。読み取りアプリケーションが重いため、レプリケーションのある環境を使用しています。ほとんどの負荷はスレーブにあります。マスターへの負荷は最小限ですが、現象はそこで発生することに気づきました。ロックの問題は発生していませんが、おそらくInnodb/Mysqlが(スレッド)の同時実行性に問題があるのでしょうか?スレーブ上の更新はシングルスレッドになることを思い出してください。

MySQL Verion 5.1.48

更新

私の場合、問題の原因は私にはあると思います。一部のサーバーでは、他のサーバーよりもこの現象に気づきました。異なるサーバー間で何が違うのかを見て、周りを調整して、私は MySQL innodbシステム変数innodb_flush_log_at_trx_commitに導かれました。

ドキュメントを読むのが少し面倒であることがわかりましたが、innodb_flush_log_at_trx_commitは1、2、0の値をとることができます。

  • 1の場合、コミットごとにログバッファーがログファイルにフラッシュされ、コミットごとにログファイルがディスクにフラッシュされます。
  • 2の場合、ログバッファーはコミットごとにログファイルにフラッシュされ、ログファイルは約1〜2秒ごとにディスクにフラッシュされます。
  • 0の場合、ログバッファは1秒ごとにログファイルにフラッシュされ、ログファイルは1秒ごとにディスクにフラッシュされます。

事実上、(1,2,0)の順序で、報告および文書化されているように、リスクの増大と引き換えにパフォーマンスの向上が得られるはずです。

そうは言っても、innodb_flush_log_at_trx_commit=0を備えたサーバーは、innodb_flush_log_at_trx_commit=2を備えたサーバーよりもパフォーマンスが低い(つまり、「長い更新」が10〜100倍多い)ことがわかりました。さらに、2に切り替えると、すぐに問題が改善されました(その場で変更できます)。

だから、私の質問は、あなたの設定は何ですか?このパラメーターを非難するのではなく、そのコンテキストがこの問題に関連していることを強調していることに注意してください。

20
Riedsio

私があなたに与える最初のヒントは、自動コミット機能を無効にし、手動でコミットすることです。

LOCK TABLES a WRITE;
... DO INSERTS HERE
UNLOCK TABLES;

これにより、すべてのINSERTステートメントが完了した後、インデックスバッファーがディスクに一度だけフラッシュされるため、パフォーマンスが向上します。通常、INSERTステートメントの数と同じ数のインデックスバッファフラッシュがあります。

しかし、できる限り最善の方法を実行できます。アプリケーションでそれが可能な場合は、1つの単一選択で一括挿入を実行します。

これは、ベクトルバインディングを介して行われます。これが最も高速な方法です。

Instead
of:
"INSERT INTO tableName values()"
DO
"INSERT INTO tableName values(),(),(),().......(n) " ,

ただし、このオプションは、使用しているmysqlドライバーでパラメーターベクトルバインディングが可能である場合にのみ検討してください。

それ以外の場合は、最初の可能性になり、1000回の挿入ごとにテーブルをロックします。バッファオーバーフローが発生するため、100kの挿入に対してロックしないでください。

1
BitKFu

INNODBテーブルを使用してこの問題が発生しました。 (INNODBインデックスはMYISAMよりも書き換えに時間がかかります)

他のいくつかのテーブルで複数の他のクエリを実行していると思うので、問題は、MySQLが大きくなるファイルのディスク書き込みを処理しなければならず、それらのファイルに追加のスペースを割り当てる必要があることです。

MYISAMテーブルを使用する場合は、

LOAD DATA INFILE 'file-on-disk' INTO TABLE `tablename` 

コマンド; MYISAMはこれでセンセーショナルに高速になり(主キーを使用しても)、ファイルをcsvとしてフォーマットし、列名を指定できます(または自動インクリメントフィールドの値としてNULLを指定できます)。

ここにMYSQLドキュメントを表示

1
Jay

400(nullではない)列のテーブルをもう1つ作成して、テストを再度実行できますか?遅い挿入の数が多くなった場合、これはMySQLがレコードの書き込みに時間を浪費していることを示している可能性があります。 (私はそれがどのように機能するか知りませんが、彼はより多くのブロックを見つけているか、断片化を避けるために何かを動かしているかもしれません...本当に知りません)

1

まったく同じ問題が発生し、ここで報告されました: http://bugs.mysql.com/bug.php?id=62381

5.1.52を使用していますが、まだ解決策がありません。このパフォーマンスヒットを回避するには、QCをオフにする必要がある場合があります。

1
fxwan

MySQL 5.1にアップグレードし、このイベント中にクエリキャッシュが多くの「アイテムの解放」の問題になりました。スレッドの状態。次に、クエリキャッシュを削除しました。

MySQL 5.1へのアップグレードまたはクエリキャッシュの削除により、この問題は解決しました。

参考までに、今後の読者の皆様へ。

-ダニエル

0
Daniel

ディスクの動作が悪いかどうか、およびWindowsを使用している場合は、10,000個のファイルを作成するバッチcmdファイルを作成できます。

@echo OFF
FOR /L %%G IN (1, 1, 10000) DO TIME /T > out%%G.txt

test.cmdのような一時ディレクトリに保存します。

/ E:ONパラメータを使用してCMDを実行するコマンド拡張機能を有効にする

CMD.exe /E:ON

次に、バッチを実行し、最初のファイルと最後のファイルの間の時間が秒または分で異なるかどうかを確認します。

Unix/Linuxでは、同様のシェルスクリプトを記述できます。

0
vulkanino

ディスクサブシステムの統計を確認できますか? I/Oは飽和していますか?これは、内部DBの作業がディスク/ログにデータをフラッシュしているように思えます。

0
bigtang

万が一サーバーにSSDドライブがありますか?一部のSSDドライブは「スタッダー」の影響を受け、症状を引き起こす可能性があります。

いずれにせよ、MySQLとディスクサブシステムのどちらで遅延が発生しているかを調べようと思います。

サーバーはどのOSで、MySQLデータはどのファイルシステムにありますか?

0
Guy Gordon

forループを使用して一度に複数の挿入を使用している場合は、PHPのsleep( "time in seconds")関数を使用してループごとに休憩してください。

0
Manish

Myisam Performanceでこれを読んでください: http://adminlinux.blogspot.com/2010/05/mysql-allocating-memory-for-caches.html

検索する:

'MyISAMキーブロックサイズキーブロックサイズは重要です'(一重引用符を除く)、これが起こっている可能性があります。 5.1でこれらのタイプの問題のいくつかを修正したと思います

0
Phill Pafford