MySQL - 简单更新很慢

Mic*_*icG 6 mysql innodb performance query-performance

我们在单个表上进行简单更新需要很长时间时遇到问题。该表包含约 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;
Run Code Online (Sandbox Code Playgroud)

这是更新查询:

UPDATE Documents
SET OperationId = 'xxxx'
WHERE SourceId = 12345
AND ParentKey = '0965b3983ceb0e8e41ab47b53e37d0f3';
Run Code Online (Sandbox Code Playgroud)

此查询更新约 80k 行,大约需要60 秒才能完成,更新的行越多,所需的时间越长,这会导致超时。索引IX_ParentKey基数是 ~830k。请注意,具有相同WHERE子句的选择返回非常快(< 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
Run Code Online (Sandbox Code Playgroud)

切换到 MyISAM 时,查询只用了2 秒。什么可能会减慢更新速度,我认为需要重建索引?有什么办法可以优化这个吗?

Ric*_*mes 5

有很多可能的解释:

  • UUID 在大表上的性能很差。

  • 的价值是innodb_buffer_pool_size什么?它应该是可用RAM 的70% 左右。缓存不佳,尤其是由于 UUID 可能会成为问题。

  • UPDATE需要INDEX(SourceId, ParentKey)(按任一顺序)。

  • 为什么在索引OperationId已经是那个长度的时候加上前缀?

  • 不要在十六进制字符串上使用 utf8。

  • BINARY(16)将UUID 打包到其中会缩小表,从而提供更快的速度。

  • 一次更新 80K 行需要付出很多努力,尤其是在规划可能的ROLLBACK. 这或许可以部分解释为什么 InnoDB 似乎比 MyISAM 慢。你会经常更新那么多行吗?听起来像是设计缺陷。