単一のテーブルの単純な更新に時間がかかっています。テーブルには約500万行が含まれます。
ここにテーブルがあります:
CREATE TABLE Documents (
GeneratedKey varchar(32) NOT NULL,
SourceId int(11) NOT NULL,
Uri longtext,
ModifiedDateUtc datetime NOT NULL,
OperationId varchar(36) DEFAULT NULL,
RowModifiedDateUtc datetime NOT NULL,
ParentKey varchar(32) NOT NULL,
PRIMARY KEY (SourceId, GeneratedKey),
KEY IX_RowModifiedDateUtc (RowModifiedDateUtc),
KEY IX_ParentKey (ParentKey),
KEY IX_OperationId (OperationId(36))
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
これが更新クエリです:
UPDATE Documents
SET OperationId = 'xxxx'
WHERE SourceId = 12345
AND ParentKey = '0965b3983ceb0e8e41ab47b53e37d0f3';
このクエリは〜80k行を更新し、完了するまでに約60秒かかります。更新する行が増えるほど、時間がかかり、タイムアウトになります。インデックスIX_ParentKey
カーディナリティは〜830kです。同じWHERE
句を使用した選択は非常に迅速に(<1秒)戻ることに注意してください。
クエリプロファイリング:
starting 0.000072
checking permissions 0.000006
Opening tables 0.000019
init 0.000023
System lock 0.000266
updating 50.415424
end 0.000039
query end 0.024398
closing tables 0.000037
freeing items 0.000051
cleaning up 0.000022
MyISAMに切り替えると、クエリは2秒しかかかりませんでした。更新が遅くなる原因は何ですか?インデックスを再構築する必要があると思いますか?これを最適化する方法はありますか?
多くの可能な説明があります:
UUIDは大きなテーブルでひどいパフォーマンスを示します。
_innodb_buffer_pool_size
_の値は? available RAMの約70%になるはずです。特にUUIDが原因の貧弱なキャッシングは問題を引き起こす可能性があります。
そのUPDATE
にはINDEX(SourceId, ParentKey)
が必要です(どちらの順序でも)。
すでにその長さのインデックスをOperationId
にプレフィックスするのはなぜですか?
16進文字列ではutf8を使用しないでください。
UUIDをBINARY(16)
にパックすると、テーブルが縮小され、速度が向上します。
特に可能性のあるROLLBACK
を計画する場合は、一度に80K行を更新するのに多くの労力がかかります。これは部分的に InnoDBがMyISAMより遅いように見える理由を説明するかもしれません。その数の行を頻繁に更新しますか?設計上の欠陥のように聞こえます。
MySQLのInnoDBは、このタイプのデータボリュームに実際にはあまり適合していません。また、可能であり、MyISAMエンジンに切り替えるための外部キーがDBにない場合もお勧めします。
その間、sourceId列とparentKey列にBTREEインデックスまたはUNIQUEインデックス、あるいはその両方を作成することで、 パフォーマンスの向上 を実行できるはずです。