web-dev-qa-db-fra.com

Comment améliorer InnoDB Supprimer les performances?

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 des articles obsolètes. La table a grandi à environ 50 millions de lignes, de sorte que le moyen le plus rapide que je puisse supprimer les lignes était de supprimer une table à la fois (basée sur tableName).

Cela fonctionne assez bien mais sur certaines des tables qui sont écrites, elle ne terminera pas. Ma requête supprime tous les articles qui ont une action associée delete sur une combinaison de 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)
)

Je laisse cela exécuter sur mon serveur pendant 3 jours et il n'est jamais terminé pour la plus grande table. La sortie Explique (si je bascule 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 supprimer, je penserais. J'ai mon innodb_buffer_pool_size défini sur 3 Go et que le serveur n'est pas défini pour utiliser One_file_per_Table. Quelles autres moyens puis-je améliorer les performances d'innoDB Supprimer? (Exécution de MySQL 5.1.43 sur Mac OSX)

9
Derek Downey
| 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 |

-Fist, de votre expliquer le key_len si gros => Vous devez dégrader la taille aussi petite que possible. Pour votre requête, je pense que le meilleur moyen est de modifier le type de données de champ d'action de Char (12) à Tinyint, de sorte que la cartographie des données ressemble à:

1: -> DELETE
2: -> UPDATE
3: -> INSERT
...

et vous pouvez changer de table_id à la place TableMename aussi. Le DDL pour la meilleure performance peut:

CREATE TABLE `track_table` (
  `id` int(11) unsigned NOT NULL,
  `userID` smallint(6) unsigned NOT NULL,
  `tableid` smallint(6) UNSIGNED NOT NULL DEFAULT 0,
  `tupleID` int(11) unsigned NOT NULL,
  `date_insert` datetime NOT NULL,
  `actionid` tinyin(4) UNSIGNED NOT NULL DEFAULT 0,
  `className` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `userID` (`userID`),
  KEY `tableID` (`tableid`,`tupleID`,`date_insert`),
  KEY `actionDate` (`actionid`,`date_insert`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE `actions` (
  `id` tinyint(4) unsigned NOT NULL 
  `actionname` varchar(255) NOT NULL,
  PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE `table_name` (
  `id` tinyint(4) unsigned NOT NULL 
  `tablename` varchar(255) NOT NULL,
  PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

afin que la requête puisse courir ressembler à:

DELETE FROM track_table WHERE tableid=@tblid AND tupleID IN (
  SELECT DISTINCT tupleID FROM track_table
  WHERE tableid=@tblid AND actionid=@actionid AND date_insert < DATE_SUB(CURDATE(), INTERVAL 30 day)
).

Mais le moyen le plus rapide utilisait la partition. Donc, vous pouvez déposer une partition. Actuellement, ma table a eu environ plus de 40 millions de rangées. et mettre à jour horaire (mise à jour des lignes de 400k 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 (<100ms). J'espère que cette aide.

1
Thanh Nguyen