Mysql

MySQL - 簡單更新很慢

  • January 21, 2022

我們在單個表上的簡單更新需要很長時間時遇到問題。該表包含約 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 慢。你會經常更新那麼多行嗎?聽起來像一個設計缺陷。

引用自:https://dba.stackexchange.com/questions/185968