MySQL'de büyük tabloya sütun nasıl eklenir


13

Ben bir PHP geliştiricisiyim bu yüzden katı olmayın. Büyük bir masam var ~ 5.5gb dökümü. Başbakanımız yeni bir özellik için yeni bir sütun yapmaya karar verdi. Tablo InnoDB yani ne denedim:

  1. Masa kilidi ile ekranda tabloyu değiştirin. ~ 30 saat aldı ve hiçbir şey. Ben de durdum. Öncelikle bir hata yaptım çünkü tüm işlemleri bitirmedim ama ikinci kez çoklu kilit yoktu. Durum böyleydi copy to tmp table.

  2. Bu tablo için bölümleme de uygulamam gerektiğinden, aynı ad ve yeni yapıya sahip döküm, yeniden adlandırma ve tablo yapmaya karar veriyoruz. Ama döküm katı kopya yapıyor (en azından başka bir şey bulamadım). Bu yüzden yeni bir sütun dökümü sedve sorgu için ekledi . Ancak bazı garip hatalar başladı. Ben charset neden olduğuna inanıyorum. Tablo utf-8 ve dosyadan sonra us-ascii oldu sed. Bu yüzden verilerin% 30'unda hatalar (bilinmeyen komut '\' ') var. Yani bu da kötü bir yol.

Bunu başarmak ve hız performansı için diğer seçenekler nelerdir (php script ile yapabilirim, ancak yaş alacak). INSERT SELECTBu durumda ne performans gösterecek .

Herhangi bir ilerleme için teşekkürler.

Yanıtlar:


12

MySQL Workbench kullanın . Bir tabloya sağ tıklayıp "SQL Düzenleyiciye Gönder" -> "Bildirim Oluştur" u seçebilirsiniz. Bu şekilde hiçbir tablonun "özelliklerinin" ( CHARSETveya dahil COLLATE) eklenmesi unutulmayacaktır .
Bu büyük miktarda veriyle, tabloyu veya kullandığınız veri yapısını temizlemenizi tavsiye ederim (iyi bir DBA kullanışlı olur). Mümkünse:

  • table ( ALTER) öğesini yeniden adlandırın ve CREATEWorkbench'ten aldığınız komut dosyasıyla yeni bir tablo oluşturun . Bu sorguyu ihtiyacınız olan yeni alanla da genişletebilirsiniz
  • Eski tablodan yenisine verileri TOPLU YÜKLE:
    SET FOREIGN_KEY_CHECKS = 0;
    SET UNIQUE_CHECKS = 0;
    SET AUTOCOMMIT = 0;
    INSERT INTO new_table (fieldA, fieldB, fieldC, ..., fieldN)
       SELECT fieldA, fieldB, fieldC, ..., fieldN
       FROM old_table
    SET UNIQUE_CHECKS = 1;
    SET FOREIGN_KEY_CHECKS = 1;
    COMMIT;

    Bu şekilde, dizine ekleme / vb. Kayıtları kayda göre çalıştırmaktan kaçınırsınız. Tabloya "güncelleme" hala (veri miktarı çok büyük olduğu gibi) yavaş olacaktır ama bu düşünebildiğim en hızlı yoludur.

    EDIT: Yukarıdaki örnek sorguda kullanılan komutlar hakkında bilgi almak için bu makaleyi okuyun ;)

Seçeneklerim iyi. Ve var SET NAMES utf8ve COLLATION.Ama meh idk neden% 30 veri sonra bozuk sed. Toplu yükün en hızlı olacağını düşünüyorum ama belki eksik olduğum bir şey daha var. Eyvallah Mark
ineersa

1
@ineersa veri bozulmasının birçok nedeni olabilir: örneğin, dosyayı tüm karakterleri desteklemeyen bir düzenleyiciyle açtınız ve kaydettiniz. Veya, dökümden içe aktarmaya çalışma şekliniz verileri bozar (buggy ve dosyayı düzgün okuyamıyor). Ya da, aynı adam bazı verilerin bir kısmını bir ifade (örn. "James \ robin" == "\ r" ifade olarak) veya komut, vb. Olarak tanımlayabilir. yalnızca dev.mysql.com/doc/refman/5.6/en/mysqldump.html (veya MS SQL Server için BCP) ile değil. Çok fazla yanlış gidiyor ...

yeap hex-blob ile denedim. yardımcı olmuyor. Ayrıca sed mysql identify \ 'komutunu bazı adlarda (hepsi değil) komut olarak kullandıktan hemen sonra. Bu garip ve buggy. Bu gece toplu yükü deneyeceğim. Umarım 10-15 saat içinde en az yapılacaktır.
ineersa

@ineersa umarım olur. verilerin yalnızca bir kısmını eklemeyi de deneyebilirsiniz, diyelim ki% 10'u ne kadar zaman aldığını görmek için - ve tüm işlem için bir tahmin yapmak. Yine de çok kaba bir tahmin olacak, önbellek / bellek / dolduğunda / aşırı yüklenirse işler yavaşlayabilir.

1
Teşekkürler Mark. Harika çalıştı. Daha da hızlı sonra dökümü geri yükleyin. ~ 5 saat sürdü.
ineersa

5

Sed fikriniz iyi bir yöntemdir, ancak çalıştırdığınız hatalar veya komut olmadan size yardımcı olamayız.

Bununla birlikte, büyük tablolarda çevrimiçi değişiklikler yapmak için iyi bilinen bir yöntem pt-online-schema-change . Bu aracın ne yaptığına dair basit bir bakış, belgelerden kopyalanır:

pt-online-schema-change tablonun değiştirilecek boş bir kopyasını oluşturarak, istendiği gibi değiştirerek ve ardından orijinal tablodan yeni tabloya satır kopyalayarak çalışır. Kopyalama tamamlandığında, orijinal tabloyu hareket ettirir ve yenisiyle değiştirir. Varsayılan olarak, orijinal tabloyu da bırakır.

Bu yöntemin de tamamlanması biraz zaman alabilir, ancak işlem sırasında orijinal tablo tamamen kullanılabilir olacaktır.


Bu gece daha sonra toplu yüklemeyi deneyeceğim. Eğer işe yaramazsa muhtemelen bu araca ihtiyaç duyacaksınız. Sed komutları kullanıldıktan sonra bazı sembollerin başlatılması hatalara neden olur. Örneğin 'D\'agostini'hataya neden olur unknown command '\''. Ancak her zaman değil, vakaların% 30'unda olduğu gibi. Bu garip ve buggy. Aynı şey altıgen damlalıklı çöplüklerle bile gelir. Teşekkür ederim Derek.
ineersa

4

alter table add column, algorithm=inplace, lock=none MySQL 5.6 tablosunu, tabloyu kopyalamadan ve kilitleme etkisi olmadan değiştirecektir.

Sadece bunu dün test ettik, kütle 280K sıra 7 bölümleme tablosuna 70K satır ekledi, her bölüme 10K satır, diğer verilere izin vermek için aralarında 5 saniye uyku vardı.

Toplu ekler başlatıldı, daha sonra ayrı oturumda alterMySQL Workbench'te yukarıdaki çevrimiçi ifadeyi başlattı, eklerden alterönce tamamlandı, iki yeni sütun eklendi ve değiştirmeden hiçbir satır sonuçlanmadı, bu da MySQL'in herhangi bir satır kopyalamadığı anlamına geliyordu.


1
Bu cevap neden daha fazla oy almıyor?
fguillen

1

Şu anda, büyük tabloları değiştirmek için en iyi seçenek muhtemelen https://github.com/github/gh-ost

gh-ost, MySQL için tetiksiz bir çevrimiçi şema geçiş çözümüdür. Test edilebilir ve duraklama, dinamik kontrol / yeniden yapılandırma, denetim ve birçok operasyonel avantaj sağlar.

gh-ost, geçiş sırasında master üzerinde, taşınan tablodaki mevcut iş yükünden ayrılan hafif bir iş yükü üretir.

Mevcut çözümlerle yılların deneyimine dayanarak tasarlandı ve masa göçlerinin paradigmasını değiştirdi.


1

Bence Mydumper / Myloader böyle işlemler için iyi bir araç: Her geçen gün daha da iyi oluyor. CPU'larınızı kullanabilir ve verileri paralel olarak yükleyebilirsiniz: http://www.percona.com/blog/2014/03/10/new-mydumper-0-6-1-release-offers-several-performance-and- kullanılabilirlik-özellikler /

Saatlerce yüzlerce gigabayt MySQL tablosu yüklemeyi başardım.

Şimdi, yeni bir sütun eklemek söz konusu olduğunda, MySQL ile tüm tabloyu bellek TMPalanına kopyaladığı için zordur ALTER TABLE...MySQL 5.6 çevrimiçi şema değişiklikleri yapabileceğini söylese de, kilitsiz büyük tablolar için bunları çevrimiçi yapmayı başaramadım çekişme henüz.


-2

Ben sadece aynı sorunu vardı. Biraz çözüm:

CREATE TABLE yeni_tablo SELECT * eskitablodan;

New_table'DAN SİL

ALTER TABLE new_table SÜTUN EKLE new_column int (11);

INSERT INTO new_table select *, 0 eski_ tablodan

açılan tablo old_table; tabloyu yeniden adlandır new_table TO old_table;


Neden herhangi bir veri seçmeyecek şekilde create table deyimine bir where cümlesi eklemiyorsunuz? Ayrıca, tabloyu
Joe W

neden daha sonra eklemek zorunda kaldığınızda tekrar silmeniz gerekir. COLUMN EKLE varsayılan = 0 tanımlayabilir.
user195280
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.