web-dev-qa-db-fra.com

MySQL - La mise à jour simple est très lente

Nous rencontrons des problèmes avec les mises à jour simples sur une seule table prenant beaucoup de temps. Le tableau contient ~ 5 millions de lignes.

Voici le tableau:

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;

Voici la requête de mise à jour:

UPDATE Documents
SET OperationId = 'xxxx'
WHERE SourceId = 12345
AND ParentKey = '0965b3983ceb0e8e41ab47b53e37d0f3';

Cette requête met à jour ~ 80k lignes et prend environ 60 secondes pour terminer, et plus il y a de lignes mises à jour, plus cela prend de temps, ce qui entraîne des délais d'attente. L'index IX_ParentKey la cardinalité est ~ 830k. Notez qu'un select avec la même clause WHERE retourne très rapidement (<1s).

Profilage des requêtes:

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

Lors du passage à MyISAM, la requête n'a pris que 2 secondes. Qu'est-ce qui pourrait ralentir les mises à jour, je suppose que l'index doit être reconstruit? Existe-t-il un moyen d'optimiser cela?

4
MicG

Il existe de nombreuses explications possibles:

  • Les UUID ont des performances terribles sur de grandes tables.

  • Quelle était la valeur de innodb_buffer_pool_size? Il devrait représenter environ 70% de disponible RAM. Une mauvaise mise en cache, en particulier à cause des UUID, pourrait poser problème.

  • Ce UPDATE a besoin de INDEX(SourceId, ParentKey) (dans l'un ou l'autre ordre).

  • Pourquoi préfixer l'index sur OperationId alors qu'il est déjà de cette longueur?

  • N'utilisez pas utf8 sur des chaînes hexadécimales.

  • Le regroupement des UUID dans BINARY(16) réduirait la table, offrant ainsi plus de vitesse.

  • La mise à jour simultanée de 80K lignes demande beaucoup d'efforts, en particulier lors de la planification d'un éventuel ROLLBACK. Cela peut partiellement expliquer pourquoi InnoDB semble être plus lent que MyISAM. Allez-vous souvent mettre à jour autant de lignes? Cela ressemble à un défaut de conception.

3
Rick James

InnoDB dans MySQL n'est vraiment pas bien adapté à ce type de volume de données. Je vous suggère également, si cela est possible et si votre base de données n'a pas de clés étrangères pour passer au moteur MyISAM.

En attendant, vous devriez pouvoir améliorer les performances en créant des index BTREE et/ou UNIQUE sur vos colonnes sourceId et parentKey.

0
Dynamite