Então, eu tenho esta tabela de auditoria (rastreia ações em qualquer tabela no meu banco de dados):
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
e preciso começar a arquivar itens desatualizados. A tabela cresceu para cerca de 50 milhões de linhas, portanto, a maneira mais rápida de excluir as linhas era excluí-la de uma tabela por vez (com base em tableName
).
Isso funciona muito bem, mas em algumas tabelas com muita gravação, ela não será concluída. Minha consulta exclui todos os itens que têm uma delete
ação associada em uma combinação 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)
)
Eu deixei isso rodar no meu servidor por 3 dias e ele nunca foi concluído para a maior tabela. A saída de explicação (se eu alternar a exclusão para selecionar:
| 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 |
Então, 4 milhões de linhas não devem levar três dias para serem excluídos, eu acho. Eu tenho meu innodb_buffer_pool_size definido como 3 GB e o servidor não está definido para usar one_file_per_table. De que outras maneiras posso melhorar o desempenho de exclusão do InnoDB? (Executando o MySQL 5.1.43 no Mac OSX)
fonte
A exclusão de linhas indesejadas no lote deve manter outra operação viável. Mas sua exclusão da operação tem condições, portanto, verifique se há um índice apropriado nas colunas sobre as condições.
Porque o MySQL não suporta a função completa de verificação de índice solta, você pode tentar ajustar a seqüência para
KEY actionDate (action, date_insert)
aKEY actionDate (date_insert, action)
. Com o prefixo 'date_insert', o MySQL deve usar esse índice para verificar as linhas anteriores à sua condição de data e hora.Com esse índice, você pode escrever SQL como:
fonte
Primeiro, a partir do seu explicar o key_len tão grande => você precisa fazer o downgrade do tamanho o menor possível. Para sua consulta, acho que a melhor maneira é alterar o tipo de dados do campo de ação de char (12) para tinyint, para que o mapeamento de dados seja semelhante a:
e você pode alterar table_id em vez de tablename também. o DDL para o melhor desempenho pode:
para que a consulta possa ser executada parecida com:
Mas a maneira mais rápida era usar a partição. então você pode soltar a partição. Atualmente, minha tabela tem mais de 40mil linhas. e atualizo a cada hora (atualização de 400 mil linhas a cada vez), e eu posso soltar a partição curr_date e recarregar os dados na tabela. o comando drop muito rápido (<100ms). Espero que esta ajuda.
fonte