Come ridurre / eliminare il file ibdata1 in MySQL


561

Sto usando MySQL in localhost come "strumento di query" per eseguire statistiche in R, ovvero ogni volta che eseguo uno script R, creo un nuovo database (A), creo una nuova tabella (B), importare i dati in B , inviare una query per ottenere ciò di cui ho bisogno, quindi rilasciare B e rilasciare A.

Funziona bene per me, ma mi rendo conto che le dimensioni del file ibdata stanno aumentando rapidamente, non ho archiviato nulla in MySQL, ma il file ibdata1 ha già superato i 100 MB.

Sto usando l'impostazione MySQL più o meno predefinita per l'installazione, c'è un modo per ridurre / eliminare automaticamente il file ibdata1 dopo un periodo di tempo fisso?


Risposte:


778

Ciò che ibdata1non si sta riducendo è una caratteristica particolarmente fastidiosa di MySQL. Il ibdata1file non può effettivamente essere ridotto a meno che non si eliminino tutti i database, si rimuovano i file e si ricarichi un dump.

Ma puoi configurare MySQL in modo che ogni tabella, compresi i suoi indici, sia memorizzata come file separato. In questo modo ibdata1non crescerà così grande. Secondo il commento di Bill Karwin, questo è abilitato di default a partire dalla versione 5.6.6 di MySQL.

È stato poco fa. Tuttavia, per configurare il server in modo da utilizzare file separati per ogni tabella, è necessario modificare my.cnfper abilitare questo:

[mysqld]
innodb_file_per_table=1

http://dev.mysql.com/doc/refman/5.5/en/innodb-multiple-tablespaces.html

Come vuoi recuperare lo spazio da ibdata1devi effettivamente eliminare il file:

  1. Esegui mysqldumptutti i database, le procedure, i trigger ecc. Tranne i database mysqleperformance_schema
  2. Eliminare tutti i database tranne i 2 database precedenti
  3. Smetti di mysql
  4. Elimina ibdata1eib_log file
  5. Inizia mysql
  6. Ripristina dalla discarica

Quando avvii MySQL al passaggio 5 , verranno ricreati i file ibdata1e ib_log.

Ora sei pronto per partire. Quando si crea un nuovo database per l'analisi, le tabelle si trovano in ibd*file separati , non in ibdata1. Poiché di solito si rilascia il database subito dopo, i ibd*file verranno eliminati.

http://dev.mysql.com/doc/refman/5.1/en/drop-database.html

Probabilmente hai visto questo:
http://bugs.mysql.com/bug.php?id=1341

Usando il comando ALTER TABLE <tablename> ENGINE=innodbo OPTIMIZE TABLE <tablename>si possono estrarre i dati e indicizzare le pagine da ibdata1 in file separati. Tuttavia, ibdata1 non si ridurrà se non si eseguono i passaggi precedenti.

Per quanto riguarda il information_schema, non è necessario né possibile abbandonare. In realtà è solo un mucchio di viste di sola lettura, non tabelle. E non ci sono file associati ad essi, nemmeno una directory di database. La informations_schemasta usando il db-motore memoria e si elimina e viene rigenerato in arresto / riavvio di mysqld. Vedi https://dev.mysql.com/doc/refman/5.7/en/information-schema.html .


16
@JordanMagnuson Non preoccuparti di eliminare information_schema. In realtà è solo un mucchio di viste di sola lettura, non tabelle. E non ci sono file associati ad essi. Non esiste nemmeno una directory per il database. Information_schema sta usando il motore di memoria db e viene eliminato e rigenerato all'arresto / riavvio di mysqld. Vedi dev.mysql.com/doc/refman/5.5/en/information-schema.html . Per quanto riguarda performance_schema non ho usato questo schema da solo.
John P

4
Non so se questa è una cosa recente ma una volta abilitata l'opzione innodb_file_per_table puoi semplicemente eseguire "ALTER TABLE <tablename> ENGINE = InnoDB" (anche se è già InnoDB) e sposterà la tabella nel suo singolo file . Non è necessario eliminare database e simili.
CR.

3
+1 FWIW, MySQL 5.6 abilita innodb_file_per_tableper impostazione predefinita.
Bill Karwin,

3
Sì, si prevede che ibdata1 sia presente insieme agli altri file. Il file ibdata1 conterrà comunque metadati relativi alle tabelle, al registro degli annullamenti e ai buffer.
John P,

1
Ho esaurito lo spazio nel mio server a causa del file ibdata1, quindi non riesco nemmeno a scaricare i database. Sarebbe lo stesso spostare i file in / var / lib / mysql (tranne "mysql", "ibdata1", "ib_logfile0" e "ib_logfile1") e quindi seguire i passaggi? Vedere stackoverflow.com/questions/2482491/...
Sophivorus

47

Aggiungendo alla risposta di John P ,

Per un sistema Linux, i passaggi 1-6 possono essere eseguiti con questi comandi:

  1. mysqldump -u [username] -p[root_password] [database_name] > dumpfilename.sql
  2. DROP DATABASE [database_name];
  3. sudo /etc/init.d/mysqld stop
  4. sudo rm /var/lib/mysql/ibdata1
    sudo rm /var/lib/mysql/ib_logfile (ed elimina eventuali altri ib_logfile che potrebbero essere nominati ib_logfile0, ib_logfile1ecc ...)
  5. sudo /etc/init.d/mysqld start
  6. create database [database_name];
  7. mysql -u [username]-p[root_password] [database_name] < dumpfilename.sql

Attenzione: queste istruzioni ti faranno perdere altri database se hai altri database su questa istanza mysql. Assicurarsi che i passaggi 1,2 e 6,7 siano modificati per coprire tutti i database che si desidera conservare.


6
È necessario ripetere 1,2 e 6 per ogni database con tabelle InnoDB.
Marchese di Lorne,

4
Hai bisogno di un altro paio di passaggi tra # 5 e # 6. Devi ricreare il database e riassegnare le autorizzazioni. Quindi dal prompt dei comandi del client mysql create database database_name;e quindigrant all privileges on database_name.* to 'username'@'localhost' identified by 'password';
fred

1
@fred Non ho avuto bisogno di concedere i privilegi durante questa operazione. Forse perché ho ricreato il database con lo stesso nome?
crmpicco,

2
Per digitare la password al Password:prompt (che è una pratica più sicura), basta inserire -psenza alcuna password effettiva.
ADTC

Trigger, eventi e routine / funzioni non vengono scaricati a meno che non si dica a mysqldump di farlo. Aggiungi anche i parametri --triggers, --events e --routines se uno dei tuoi database li contiene. Inoltre, basta eseguire il dump con --all-database per scaricare tutti i database contemporaneamente anziché uno per uno.
Friek,

34

Quando elimini tabelle innodb, MySQL non libera lo spazio all'interno del file ibdata, ecco perché continua a crescere. Questi file non si restringono quasi mai.

Come ridurre un file ibdata esistente:

http://dev.mysql.com/doc/refman/5.5/en/innodb-resize-system-tablespace.html

È possibile eseguire lo script e pianificare l'esecuzione dello script dopo un periodo di tempo prestabilito, ma per l'installazione sopra descritta sembra che più tablespace siano una soluzione più semplice.

Se si utilizza l'opzione di configurazione innodb_file_per_table, si creano più tablespace. Cioè, MySQL crea file separati per ogni tabella anziché un file condiviso. Questi file separati vengono archiviati nella directory del database e vengono eliminati quando si elimina questo database. Questo dovrebbe rimuovere la necessità di ridurre / eliminare i file ibdata nel tuo caso.

Ulteriori informazioni su più tablespace:

http://dev.mysql.com/doc/refman/5.5/en/innodb-multiple-tablespaces.html


primo collegamento interrotto, corrispondenza più vicina che ho trovato: dev.mysql.com/doc/refman/5.5/en/…
BlackICE,

14

Se usi il motore di archiviazione InnoDB per (alcune) delle tue tabelle MySQL, probabilmente hai già riscontrato un problema con la sua configurazione predefinita. Come avrai notato nella directory dei dati di MySQL (in Debian / Ubuntu - / var / lib / mysql) si trova un file chiamato 'ibdata1'. Contiene quasi tutti i dati InnoDB (non è un registro delle transazioni) dell'istanza MySQL e potrebbe diventare piuttosto grande. Per impostazione predefinita, questo file ha una dimensione iniziale di 10 Mb e si estende automaticamente. Purtroppo, in base alla progettazione, i file di dati di InnoDB non possono essere ridotti. Ecco perché DELETE, TRUNCATE, DROPs, ecc. Non recupereranno lo spazio utilizzato dal file.

Penso che puoi trovare buone spiegazioni e soluzioni lì:

http://vdachev.net/2007/02/22/mysql-reducing-ibdata1/


11

Scritto rapidamente la procedura della risposta accettata in bash:

#!/usr/bin/env bash
DATABASES="$(mysql -e 'show databases \G' | grep "^Database" | grep -v '^Database: mysql$\|^Database: binlog$\|^Database: performance_schema\|^Database: information_schema' | sed 's/^Database: //g')"
mysqldump --databases $DATABASES -r alldatabases.sql && echo "$DATABASES" | while read -r DB; do
    mysql -e "drop database \`$DB\`"
done && \
    /etc/init.d/mysql stop && \
    find /var/lib/mysql -maxdepth 1 -type f \( -name 'ibdata1' -or -name 'ib_logfile*' \) -delete && \
    /etc/init.d/mysql start && \
    mysql < alldatabases.sql && \
    rm -f alldatabases.sql

Salva come purge_binlogs.shed esegui comeroot .

Esclude mysql, information_schema, performance_schema(ebinlog directory).

Presuppone che tu abbia credenziali di amministratore /root/.my.cnfe che il tuo database risulti predefinito/var/lib/mysql directory .

È inoltre possibile eliminare i registri binari dopo aver eseguito questo script per recuperare più spazio su disco con:

PURGE BINARY LOGS BEFORE CURRENT_TIMESTAMP;

Ancora non so perché, ma oggi alcune delle mie tabelle InnoDB sono state danneggiate durante un processo simile, quindi non rimuoverò alldatabases.sqlprima di ricontrollare se tutte le tabelle sono integre. Per quanto riguarda alcuni miglioramenti: impostare innodb_fast_shutdown=0prima dell'arresto, impostare autocommit=0prima dell'importazione del file SQL, eseguire COMMITe impostare autocommit=1dopo l'importazione del file SQL, utilizzare mysqlcheck --all-databasesprima di eliminare il backup.
Victor,

6

Se il tuo obiettivo è monitorare lo spazio libero di MySQL e non puoi impedire a MySQL di ridurre il tuo file ibdata, procuralo tramite i comandi di stato della tabella. Esempio:

MySQL> 5.1.24:

mysqlshow --status myInnodbDatabase myTable | awk '{print $20}'

MySQL <5.1.24:

mysqlshow --status myInnodbDatabase myTable | awk '{print $35}'

Quindi confronta questo valore con il tuo file ibdata:

du -b ibdata1

Fonte: http://dev.mysql.com/doc/refman/5.1/en/show-table-status.html


4

In una nuova versione delle ricette di mysql-server sopra, il database "mysql" verrà schiacciato. Nella vecchia versione funziona. In alcune nuove tabelle si passa al tipo di tabella INNODB e, in tal modo, le si danneggerà. Il modo più semplice è:

  • scaricare tutti i database
  • disinstallare mysql-server,
  • aggiungi in rimasto my.cnf:
    [mysqld]
    innodb_file_per_table=1
  • cancella tutto in / var / lib / mysql
  • installa mysql-server
  • ripristinare utenti e database

1

Come già notato, non è possibile ridurre ibdata1 (per fare ciò è necessario scaricare e ricostruire), ma spesso non è nemmeno necessario.

Usando autoextend (probabilmente l'impostazione di dimensione più comune) ibdata1 prealloca lo spazio di archiviazione, aumentando ogni volta che è quasi pieno. Ciò rende le scritture più veloci poiché lo spazio è già allocato.

Quando si eliminano i dati, questi non si riducono ma lo spazio all'interno del file viene contrassegnato come inutilizzato. Ora, quando si inseriscono nuovi dati, riutilizzeranno lo spazio vuoto nel file prima di espandere ulteriormente il file.

Quindi continuerà a crescere solo se in realtà hai bisogno di quei dati. A meno che non sia effettivamente necessario lo spazio per un'altra applicazione, probabilmente non c'è motivo di ridurlo.


66
Penso che tu sia un po 'troppo sprezzante per la necessità di liberare spazio.
sorteggiato il

2
Ho una partizione a stato solido 60Gig. Ho esaurito lo spazio velocemente, dal momento che lavoro con 4 + database di concerti. Sto cercando di spostare presto mysql in un'altra partizione, ma questa domanda e le sue risposte mi aiuteranno nel frattempo
NullVoxPopuli

3
Grazie per questa risposta, è molto utile. Ho cancellato alcune tabelle dai dati legacy ... è bene sapere che le dimensioni sul disco non cresceranno di nuovo presto.
Brad

1
Ho un file ibdata1 500G - ma quasi tutti i dati che sono stati memorizzati sono ora archiviati in file per database. Ho davvero bisogno di ridurre questo collossale spreco di spazio!
Frank

2
Assurdità completa! Un file che continua a gonfiarsi deve essere tagliato indipendentemente dal fatto che tu stia esaurendo lo spazio o meno . Lo chiamerei a storage leak.
ADTC,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.