MySQL'de ibdata1 dosyasını küçültme / temizleme


561

Localhost'ta MySQL'i R'de istatistik yapmak için bir "sorgu aracı" olarak kullanıyorum, yani her R komut dosyası çalıştırdığımda yeni bir veritabanı (A) oluşturuyorum, yeni bir tablo (B) oluşturuyorum, verileri B'ye aktarıyorum , ihtiyacım olanı almak için bir sorgu gönderin ve sonra B'yi ve A'yı bıraktım.

Benim için iyi çalışıyor, ancak ibdata dosya boyutunun hızla arttığını fark ettim, MySQL'de hiçbir şey saklamadım, ancak ibdata1 dosyası zaten 100 MB'ı aştı.

Kurulum için daha fazla veya daha az varsayılan MySQL ayarı kullanıyorum, otomatik olarak belirli bir süre sonra ibdata1 dosyasını küçültme / temizleme için bir yol var mı?


Yanıtlar:


777

Bu ibdata1daralma değil, MySQL'in özellikle can sıkıcı bir özelliğidir. ibdata1Dosyanın gerçekten, tüm veritabanlarını silmek dosyaları kaldırmak ve bir dökümü yeniden sürece küçüldü yapılamaz.

Ancak MySQL'i, dizinleri de dahil olmak üzere her tablonun ayrı bir dosya olarak saklanacağı şekilde yapılandırabilirsiniz. Bu şekilde ibdata1büyüyemez. Bill Karwin'in yorumuna göre, bu MySQL'in 5.6.6 sürümünden itibaren varsayılan olarak etkindir.

Bunu bir süre önce yaptım. Ancak, sunucunuzu her tablo için ayrı dosyalar kullanacak şekilde ayarlamak için, my.cnfaşağıdakileri etkinleştirmek üzere değiştirmeniz gerekir :

[mysqld]
innodb_file_per_table=1

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

Sizden alanı geri almak istediğinizde ibdata1, dosyayı silmek zorundasınız:

  1. Ve veritabanları hariçmysqldump tüm veritabanlarını, yordamları, tetikleyicileri vb. Yapın .mysqlperformance_schema
  2. Yukarıdaki 2 veritabanı hariç tüm veritabanlarını bırakın
  3. MySQL'i durdur
  4. Sil ibdata1ve ib_logdosyalar
  5. MySQL'i başlat
  6. Dökümden geri yükle

5. adımda MySQL'i başlattığınızda ibdata1ve ib_logdosyaları yeniden oluşturulur.

Artık hazırsınız. Analiz için yeni bir veritabanı oluşturduğunuzda, tablolar içinde ibd*değil ayrı dosyalarda bulunur ibdata1. Genellikle veritabanını kısa süre sonra bıraktığınız için ibd*dosyalar silinir.

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

Muhtemelen bunu gördünüz:
http://bugs.mysql.com/bug.php?id=1341

Komut ALTER TABLE <tablename> ENGINE=innodbveya OPTIMIZE TABLE <tablename>birini kullanarak verileri ve dizin sayfalarını ibdata1'den ayrı dosyalara ayıklayabilirsiniz. Ancak, yukarıdaki adımları uygulamadığınız sürece ibdata1 küçülmez.

information_schemaBununla ilgili olarak , düşürmek gerekli ya da mümkün değildir. Aslında sadece bir demet salt okunur görünümler, tablolar değil. Ve onlarla ilişkili hiçbir dosya yok, hatta bir veritabanı dizini bile yok. Bu informations_schemabellek db-engine kullanıyor ve mysqld durdur / yeniden başlat üzerine düşürülür ve rejenere edilir. Bkz. Https://dev.mysql.com/doc/refman/5.7/en/information-schema.html .


16
@JordanMagnuson information_schema bırakmak için uğraşmayın. Aslında sadece bir demet salt okunur görünümler, tablolar değil. Ve bunlarla ilişkili hiçbir dosya yok. Veritabanı için bir dizin bile yok. İnformations_schema, db-engine belleğini kullanıyor ve mysqld'in durdurulması / yeniden başlatılması üzerine düşürülüyor ve yeniden oluşturuluyor. Bkz. Dev.mysql.com/doc/refman/5.5/en/information-schema.html . Performance_schema ile ilgili olarak ben bu şemayı kendim kullanmadım.
John P

4
Bu yeni bir şey olup olmadığını bilmiyorum ama innodb_file_per_table seçeneği etkinleştirildikten sonra sadece "ALTER TABLE <tablename> ENGINE = InnoDB" (zaten InnoDB olsa bile) çalıştırabilirsiniz ve tabloyu kendi dosyasına taşıyacak . Veritabanlarını ve benzeri şeyleri bırakmaya gerek yoktur.
CR.

3
+1 FWIW, MySQL 5.6 innodb_file_per_tablevarsayılan olarak etkindir.
Bill Karwin

3
Evet, ibdata1'in diğer dosyalarla birlikte bulunması bekleniyor. İbdata1 dosyası yine de tablolar, geri alma günlüğü ve arabellekler hakkındaki meta verileri tutar.
John P

1
İbdata1 dosyası nedeniyle sunucumda yer kalmadı, bu yüzden veritabanlarını bile dökemiyorum. Dosyaları sadece / var / lib / mysql ("mysql", "ibdata1", "ib_logfile0" ve "ib_logfile1" hariç) taşımak ve ardından adımları izlemek aynı mıdır? Bkz. Stackoverflow.com/questions/2482491/…
Sophivorus

47

Ekleme John P cevabı ,

Linux sistemi için 1-6 arası adımlar şu komutlarla gerçekleştirilebilir:

  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 (ve adlandırılmış olabilir başka ib_logfile 's silmek ib_logfile0, ib_logfile1vb ...)
  5. sudo /etc/init.d/mysqld start
  6. create database [database_name];
  7. mysql -u [username]-p[root_password] [database_name] < dumpfilename.sql

Uyarı: Bu talimatlar, bu mysql örneğinde başka veritabanlarınız varsa diğer veritabanlarını kaybetmenize neden olur. 1,2 ve 6,7 adımlarının saklamak istediğiniz tüm veritabanlarını kapsayacak şekilde değiştirildiğinden emin olun.


6
InnoDB tabloları olan her veritabanı için 1,2 ve 6'yı tekrarlamanız gerekir.
Lorne Marquis

4
# 5 ve # 6 arasında birkaç adım daha atmanız gerekiyor. Veritabanını yeniden oluşturmanız ve izinleri yeniden atamanız gerekir. Yani mysql istemci komut isteminden create database database_name;ve sonragrant all privileges on database_name.* to 'username'@'localhost' identified by 'password';
fred

1
@ fred Bunu yaparken ayrıcalık vermem gerekmiyordu. Aynı adla veritabanını yeniden oluşturduğum için mi?
crmpicco

2
Parolayı bir Password:istemde yazmak için (daha güvenli bir uygulamadır), -pgerçek parola olmadan girmeniz yeterlidir.
ADTC

Eğer mysqldump'a bunu söylemezseniz, tetikleyiciler, olaylar ve rutinler / işlevler dökülmez. Veritabanlarınızdan herhangi biri bunları içeriyorsa --triggers, --events ve --routines öğelerini ekleyin. Ayrıca, tüm veritabanlarını tek tek yerine tek seferde boşaltmak için --all-veritabanları ile dökün.
Friek

34

Innodb tablolarını sildiğinizde, MySQL ibdata dosyasının içindeki alanı boşaltmaz, bu yüzden büyümeye devam eder. Bu dosyalar neredeyse hiç küçülmez.

Mevcut bir ibdata dosyası nasıl küçültülür:

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

Bunu kodlayabilir ve komut dosyasını belirli bir süre sonra çalışacak şekilde zamanlayabilirsiniz, ancak yukarıda açıklanan kurulum için birden çok tablo alanının daha kolay bir çözüm olduğu görülmektedir.

Yapılandırma seçeneğini kullanırsanız, innodb_file_per_tablebirden çok tablo alanı oluşturursunuz. Yani, MySQL her tablo için bir paylaşılan dosya yerine ayrı dosyalar oluşturur. Bu dosyalar veritabanının dizininde saklanan dosyaları ayırır ve bu veritabanını sildiğinizde silinir. Bu, davanızdaki ibdata dosyalarını küçültme / temizleme ihtiyacını ortadan kaldırmalıdır.

Birden çok tablo alanı hakkında daha fazla bilgi:

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


ilk bağlantı kırık, en yakın eşleşme bulabildiğim: dev.mysql.com/doc/refman/5.5/en/…
BlackICE

14

MySQL tablolarınız için (bazıları) InnoDB depolama motorunu kullanırsanız, muhtemelen varsayılan yapılandırmasında bir sorunla karşılaşmışsınızdır. MySQL'inizin veri dizininde (Debian / Ubuntu - / var / lib / mysql) fark etmiş olabileceğiniz gibi 'ibdata1 ′ adlı bir dosya yatıyor. MySQL örneğinin neredeyse tüm InnoDB verilerini (bir işlem günlüğü değil) tutar ve oldukça büyük olabilir. Varsayılan olarak bu dosyanın başlangıç ​​boyutu 10Mb'dir ve otomatik olarak genişletilir. Ne yazık ki, tasarım gereği InnoDB veri dosyaları küçültülemez. Bu nedenle DELETE'ler, TRUNCATE'ler, DROP'ler vb. Dosya tarafından kullanılan alanı geri almayacaktır.

Bence orada iyi bir açıklama ve çözüm bulabilirsiniz:

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


11

Kabul edilen yanıtın prosedürünü bash olarak hızlıca komut verdi:

#!/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

Farklı kaydet purge_binlogs.shve farklı çalıştır root.

Hariçtir mysql, information_schema, performance_schema(ve binlogdizin).

Yönetici kimlik bilgilerine sahip /root/.my.cnfolduğunuzu ve veritabanınızın varsayılan /var/lib/mysqldizinde yaşadığını varsayar .

Ayrıca, daha fazla disk alanı kazanmak için bu komut dosyasını çalıştırdıktan sonra ikili günlükleri temizleyebilirsiniz:

PURGE BINARY LOGS BEFORE CURRENT_TIMESTAMP;

Hala neden emin değilim, ama bugün bazı InnoDB tabloları benzer bir işlem sırasında bozuldu, bu yüzden alldatabases.sqltüm tablolar sağlıklı olup olmadığını iki kez kontrol etmeden önce kaldırmak olmaz . Bazı geliştirmelere gelince: innodb_fast_shutdown=0kapatmadan önce ayarlayın , autocommit=0SQL dosyasını içe aktarmadan önce ayarlayın, SQL dosyasını içe aktardıktan sonra yürütün COMMITve ayarlayın autocommit=1, mysqlcheck --all-databasesyedeklemeyi silmeden önce kullanın .
Victor

6

Amacınız MySQL boş alanını izlemekse ve ibdata dosyanızı küçültmek için MySQL'i durduramıyorsanız, tablo durum komutları aracılığıyla alın. Misal:

MySQL> 5.1.24:

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

MySQL <5.1.24:

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

Ardından bu değeri ibdata dosyanızla karşılaştırın:

du -b ibdata1

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


4

Yukarıdaki mysql-sunucu tarifleri yeni bir sürümünde "mysql" veritabanı ezmek olacaktır. Eski versiyonda çalışır. Yeni bazı tablolarda INNODB tablo türüne geçer ve bu şekilde tablolara zarar verebilirsiniz. En kolay yol:

  • tüm veritabanlarını boşalt
  • mysql sunucusunu kaldır,
  • kalan my.cnf ekleyin:
    [mysqld]
    innodb_file_per_table=1
  • / var / lib / mysql içindeki tümünü sil
  • mysql-server kur
  • kullanıcıları ve veritabanlarını geri yükle

1

Daha önce de belirtildiği gibi ibdata1'i küçültemezsiniz (bunu yapmak için dökmeniz ve yeniden inşa etmeniz gerekir), ancak çoğu zaman gerçek bir ihtiyaç yoktur.

Otomatik uzatma (muhtemelen en yaygın boyut ayarı) kullanılarak ibdata1, neredeyse her dolduğunda büyüyen depolamayı önceden konumlandırır. Bu, alan ayrıldığı için yazma işlemlerini hızlandırır.

Verileri sildiğinizde küçülmez ancak dosyanın içindeki boşluk kullanılmamış olarak işaretlenir. Artık yeni veri eklediğinizde, dosyayı daha da büyütmeden önce dosyadaki boş alanı yeniden kullanır.

Bu nedenle, yalnızca bu verilere gerçekten ihtiyacınız varsa büyümeye devam edecektir. Başka bir uygulama için alana ihtiyacınız olmadığı sürece, küçültmek için muhtemelen bir neden yoktur.


66
Sanırım alanı boşaltma ihtiyacından biraz fazla küçümsersiniz.
42 drewish

2
60Gig Katı Hal bölümüm var. 4 + gig veritabanlarıyla çalıştığım için alanım hızlı tükeniyor. Yakında başka bir bölüme mysql taşımak için arıyorum, ama bu soru ve cevapları bu arada bana yardımcı olacaktır
NullVoxPopuli

3
Bu cevap için teşekkür ederim, çok faydalı. Bazı tabloları eski verilerden temizledim ... diskteki boyutun yakın zamanda tekrar büyümeyeceğini bilmek güzel.
Brad

1
500G ibdata1 dosyası var - ancak içinde depolanan verilerin neredeyse tamamı artık veritabanı başına dosyalarda saklanıyor. Bu muazzam alan israfını küçültmem gerek!
frankster

2
Tamamen saçmalık! Boş alanınız olsun veya olmasın , şişmeye devam eden bir dosyanın kırpılması gerekir . Buna a diyorum . storage leak
ADTC
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.