J'ai donc cette table d'audit (suit les actions sur n'importe quelle table de ma base de données):
CREATE TABLE `track_table` (
`id` int(16) unsigned NOT NULL,
`userID` smallint(16) unsigned NOT NULL,
`tableName` varchar(255) NOT NULL DEFAULT '',
`tupleID` int(16) unsigned NOT NULL,
`date_insert` datetime NOT NULL,
`action` char(12) NOT NULL DEFAULT '',
`className` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `userID` (`userID`),
KEY `tableID` (`tableName`,`tupleID`,`date_insert`),
KEY `actionDate` (`action`,`date_insert`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
et je dois commencer à archiver les éléments obsolètes. La table est passée à environ 50 millions de lignes, donc la façon la plus rapide de supprimer les lignes était de la supprimer une table à la fois (en fonction de tableName
).
Cela fonctionne assez bien, mais sur certains tableaux qui sont lourds en écriture, il ne se terminera pas. Ma requête supprime tous les éléments qui ont une delete
action associée sur une combinaison tupleID / tableName:
DELETE FROM track_table WHERE tableName='someTable' AND tupleID IN (
SELECT DISTINCT tupleID FROM track_table
WHERE tableName='someTable' AND action='DELETE' AND date_insert < DATE_SUB(CURDATE(), INTERVAL 30 day)
)
J'ai laissé cela fonctionner sur mon serveur pendant 3 jours et cela ne s'est jamais terminé pour la plus grande table. La sortie d'explication (si je commute la suppression pour sélectionner:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
| 1 | PRIMARY | track_table | ref | tableID | tableID | 257 | const | 3941832 | Using where |
| 2 | DEPENDENT SUBQUERY | track_table | ref | tableID,actionDate | tableID | 261 | const,func | 1 | Using where; Using temporary |
Donc, 4 millions de lignes ne devraient pas prendre 3 jours pour être supprimées, je pense. J'ai mon innodb_buffer_pool_size défini sur 3 Go, et le serveur n'est pas configuré pour utiliser one_file_per_table. De quelles autres manières puis-je améliorer les performances de suppression d'InnoDB? (Exécution de MySQL 5.1.43 sur Mac OSX)
la source
La suppression de lignes indésirables dans le lot devrait permettre à d'autres opérations de fonctionner. Mais votre suppression d'opération a des conditions, assurez-vous donc qu'il existe un index approprié sur les colonnes par rapport aux conditions.
Parce que MySQL ne supporte pas la fonction complète de balayage libre d'index, vous pouvez essayer d'ajuster la séquence pour
KEY actionDate (action, date_insert)
laKEY actionDate (date_insert, action)
. Avec le préfixe 'date_insert', MySQL devrait utiliser cet index pour analyser les lignes qui sont antérieures à votre condition datetime.Avec un tel index, vous pouvez écrire SQL comme:
la source
-Pistez, à partir de votre explication du key_len si grand => vous devez rétrograder la taille aussi petite que possible. Pour votre requête, je pense que le meilleur moyen est de changer le type de données du champ d'action de char (12) en tinyint, de sorte que le mappage des données ressemble à:
et vous pouvez également changer table_id à la place nom_table. le DDL pour les meilleures performances peut:
de sorte que la requête puisse fonctionner comme:
Mais le moyen le plus rapide était d'utiliser la partition. afin que vous puissiez supprimer la partition. Actuellement, ma table compte plus de 40 mil de lignes. et mettre à jour toutes les heures (400k lignes de mise à jour pour chaque fois), et je peux déposer la partition curr_date et recharger les données dans la table. la commande drop très rapide (<100 ms). J'espère que cette aide.
la source