Mysql
MySQL - 簡單更新很慢
我們在單個表上的簡單更新需要很長時間時遇到問題。該表包含約 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
子句的 select 返回非常快(< 1s)。查詢分析:
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
多少?它應該是可用RAM 的 70% 左右。記憶體不佳,尤其是由於 UUID 可能是一個問題。- 這
UPDATE
需要INDEX(SourceId, ParentKey)
(以任意順序)。OperationId
當它已經是那個長度時,為什麼要在索引上加上前綴?- 不要在十六進製字元串上使用 utf8。
- 將UUID 打包到
BINARY(16)
其中會縮小表,從而提供更快的速度。- 一次更新 80K 行需要付出很多努力,尤其是在計劃可能的
ROLLBACK
. 這可以部分解釋為什麼 InnoDB 似乎比 MyISAM 慢。你會經常更新那麼多行嗎?聽起來像一個設計缺陷。