Entonces tengo esta tabla de auditoría (rastrea acciones en cualquier tabla de mi base de datos):
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
y necesito comenzar a archivar elementos obsoletos. La tabla ha crecido a aproximadamente 50 millones de filas, por lo que la forma más rápida en que podía eliminar las filas era eliminarla de una tabla a la vez (según tableName
).
Esto funciona bastante bien, pero en algunas de las tablas que requieren mucha escritura, no se completará. Mi consulta elimina todos los elementos que tienen una delete
acción asociada en una combinación 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)
)
Dejé que esto se ejecute en mi servidor durante 3 días y nunca se completó para la tabla más grande. La salida de explicación (si cambio la eliminación para seleccionar:
| 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 |
Entonces, 4 millones de filas no deberían tomar 3 días para eliminar, creo. Tengo mi innodb_buffer_pool_size establecido en 3GB, y el servidor no está configurado para usar one_file_per_table. ¿De qué otras formas puedo mejorar el rendimiento de eliminación de InnoDB? (Ejecutando MySQL 5.1.43 en Mac OSX)
fuente
La eliminación de filas no deseadas en el lote debería permitir que otras operaciones funcionen. Pero su eliminación de la operación tiene condiciones, así que asegúrese de que haya un índice apropiado en las columnas sobre las condiciones.
Debido a que MySQL no soporta la función completa del recorrido de índice suelta, se puede tratar de ajustar la secuencia de
KEY actionDate (action, date_insert)
aKEY actionDate (date_insert, action)
. Con el prefijo 'date_insert', MySQL debería usar este índice para escanear las filas que son anteriores a su condición de fecha y hora.Con dicho índice, puede escribir SQL como:
fuente
-Puño, desde su explicación key_len tan grande => necesita degradar el tamaño lo más pequeño posible. Para su consulta, creo que la mejor manera es cambiar el tipo de datos del campo de acción de char (12) a tinyint, para que el mapeo de datos se vea así:
y también puedes cambiar table_id en lugar de tablename. El DDL para el mejor rendimiento puede:
para que la consulta pueda ejecutarse así:
Pero la forma más rápida fue usando la partición. para que puedas soltar la partición. Actualmente, mi mesa tiene más de 40mil filas. y actualizar cada hora (400k filas de actualización para cada vez), y puedo soltar la partición curr_date y volver a cargar los datos en la tabla. el comando soltar muy rápido (<100 ms). Espero que esto ayude.
fuente