Tablo kilitleme olmadan büyük bir MySQL üretim tablosunda bir dizin oluşturun


106

~ 5M satırlık bir MySQL tablosunda bir dizin oluşturmam gerekiyor. Bu bir üretim tablosu ve bir CREATE INDEX ifadesi çalıştırırsam her şeyin tamamen engellenmesinden korkuyorum ...

Eklemeleri ve seçimleri engellemeden bu dizini oluşturmanın bir yolu var mı?

Merak ediyorum, durmamam, dizin oluşturmamam ve sistemimi yeniden başlatmamam gerekiyor!


1
myisam_sort_buffer_size ve myisam_max_sort_file_size değerinizin yeterince büyük olduğundan emin olun.
Jon Black

Yanıtlar:


132

[2017] Güncelleme: MySQL 5.6, çevrimiçi dizin güncellemelerini destekliyor

https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html#online-ddl-index-syntax-notes

MySQL 5.6 ve daha yüksek sürümlerde, dizin oluşturulurken veya bırakılırken tablo okuma ve yazma işlemleri için kullanılabilir durumda kalır. CREATE INDEX veya DROP INDEX deyimi, yalnızca tabloya erişen tüm işlemler tamamlandıktan sonra biter, böylece dizinin başlangıç ​​durumu tablonun en son içeriğini yansıtır. Daha önce, bir dizin oluşturulurken veya bırakılırken tabloyu değiştirmek, genellikle tablodaki INSERT, UPDATE veya DELETE deyimini iptal eden bir kilitlenmeyle sonuçlanıyordu.

[2015] Tablonun güncellenmesi blokların MySQL 5.5'te yazdıklarını gösterir

Yukarıdaki cevaptan:

"Veritabanı çevrimiçiyken 5.1 indekslerden daha büyük bir sürüm kullanıyorsanız oluşturulur. Bu yüzden endişelenmeyin, üretim sistemi kullanımını kesintiye uğratmayacaksınız."

Bu **** YANLIŞ **** (en azından MyISAM / InnoDB tabloları için, oradaki insanların% 99,999'unun kullandığı şeydir. Clustered Edition farklıdır.)

Bir tablo üzerinde UPDATE işlemleri yapmak olacaktır BLOK endeks oluşturulurken. MySQL bu konuda gerçekten çok aptalca (ve birkaç başka şey).

Test Komut Dosyası:

(   
  for n in {1..50}; do
    #(time mysql -uroot -e 'select  * from website_development.users where id = 41225\G'>/dev/null) 2>&1 | grep real;
    (time mysql -uroot -e 'update website_development.users set bio="" where id = 41225\G'>/dev/null) 2>&1 | grep real;
  done
) | cat -n &
PID=$!
sleep 0.05
echo "Index Update - START"
mysql -uroot website_development -e 'alter table users add index ddopsonfu (last_name, email, first_name, confirmation_token, current_sign_in_ip);'
echo "Index Update - FINISH"
sleep 0.05
kill $PID
time mysql -uroot website_development -e 'drop index ddopsonfu on users;'

Sunucum (InnoDB):

Server version: 5.5.25a Source distribution

Çıktı (dizin güncellemesini bitirmek için gereken ~ 400 ms için 6. işlemin nasıl bloke edildiğine dikkat edin):

 1  real    0m0.009s
 2  real    0m0.009s
 3  real    0m0.009s
 4  real    0m0.012s
 5  real    0m0.009s
Index Update - START
Index Update - FINISH
 6  real    0m0.388s
 7  real    0m0.009s
 8  real    0m0.009s
 9  real    0m0.009s
10  real    0m0.009s
11  real    0m0.009s

Vs, engellemeyen işlemleri okuma (komut dosyasındaki satır açıklamasını değiştirin):

 1  real    0m0.010s
 2  real    0m0.009s
 3  real    0m0.009s
 4  real    0m0.010s
 5  real    0m0.009s
Index Update - START
 6  real    0m0.010s
 7  real    0m0.010s
 8  real    0m0.011s
 9  real    0m0.010s
...
41  real    0m0.009s
42  real    0m0.010s
43  real    0m0.009s
Index Update - FINISH
44  real    0m0.012s
45  real    0m0.009s
46  real    0m0.009s
47  real    0m0.010s
48  real    0m0.009s

MySQL'in Şemasını kesinti olmadan güncelleme

Dolayısıyla, bir MySql şemasını güncellemek ve kullanılabilirlik kesintisine uğramamak için bildiğim tek bir yöntem var. Dairesel ustalar:

  • Master A, MySQL veritabanınız üzerinde çalışıyor
  • Usta B'yi hizmete sokun ve Usta A'dan gelen yazıları çoğaltmasını sağlayın (B, A'nın kölesidir)
  • Ana B'de şema güncellemesini gerçekleştirin. Yükseltme sırasında geride kalacak
  • Bırakın Usta B yetişsin. Değişmez: Şema değişikliğiniz bir downversion şemasından çoğaltılan komutları işleyebilmelidir ZORUNLU. Dizin oluşturma değişiklikleri uygun. Basit sütun eklemeleri genellikle uygun olur. Bir sütunu kaldırmak mı? muhtemelen değil.
  • Atomik olarak sen (güven bana, do), sen A'ya son yazma B'ye çoğaltılır emin olmalıdır güvenli olmasını istiyorsanız Usta B'ye Usta A'dan tüm istemcilerin takas ÖNCEB ilk yazısını alıyor. 2+ master için eşzamanlı yazma işlemlerine izin verirseniz, ... MySQL replikasyonunu DERİN seviyesinde daha iyi anlarsınız veya acı dolu bir dünyaya yönelirsiniz. Aşırı acı. Gibi, AUTOINCREMENT olan bir sütununuz var mı ??? Batırırsınız (bir ana bilgisayarda çift sayılar ve diğerinde oran kullanmadığınız sürece). MySQL replikasyonuna "doğru olanı yapmak" için GÜVENMEYİN. Akıllı DEĞİL ve seni kurtarmayacak. İkili işlem günlüklerini komut satırından kopyalayıp elle yeniden yürütmekten biraz daha az güvenlidir. Yine de, tüm istemcilerin eski ana yöneticiden bağlantısını kesmek ve onları yeni ana yöneticiye çevirmek, birkaç saatlik bir şema yükseltmesini beklemekten çok daha hızlı bir şekilde saniyeler içinde yapılabilir.
  • Şimdi Usta B yeni üstadınız. Yeni şemaya sahipsiniz. Hayat güzel. Bir bira iç; en kötüsü bitti.
  • Süreci Usta A ile tekrarlayın, şemasını yeni ikincil üstadınız olacak şekilde yükseltin, birincil ustanızın (şimdi usta B) gücünü kaybetmesi veya sadece sizin üzerinizden ölmesi durumunda devralmaya hazır.

Şemayı güncellemenin kolay bir yolu bu değil. Ciddi bir üretim ortamında uygulanabilir; Evet öyle. Lütfen, lütfen, lütfen, yazmaları engellemeden bir MySQL tablosuna dizin eklemenin daha kolay bir yolu varsa, bana bildirin.

Googling beni benzer bir tekniği anlatan bu makaleye yönlendiriyor. Daha da iyisi, işlemde aynı noktada içmeyi tavsiye ediyorlar (Cevabımı makaleyi okumadan önce yazdığımı unutmayın)!

Percona'nın pt-çevrimiçi-şema değişikliği

Makale Bir araç hakkında görüşmelerde yukarıda bağlantılı, pt-online-şema değişikliği , yani aşağıdaki gibi çalışır:

  • Orijinalle aynı yapıya sahip yeni tablo oluşturun.
  • Yeni tabloda şemayı güncelleyin.
  • Orijinal tabloya bir tetikleyici ekleyin, böylece değişikliklerin kopyayla senkronize kalması
  • Orijinal tablodan gruplar halinde satırları kopyalayın.
  • Orijinal masayı ortadan kaldırın ve yeni masayla değiştirin.
  • Eski masayı bırak.

Aracı kendim hiç denemedim. YMMV

RDS

Şu anda Amazon'un RDS'si aracılığıyla MySQL kullanıyorum . MySQL'i tamamlayan ve yöneten, tek bir düğmeyle yeni okuma replikaları eklemenize ve veritabanını donanım SKU'ları arasında şeffaf bir şekilde yükseltmenize olanak tanıyan gerçekten şık bir hizmettir. Gerçekten uygun. Veritabanına SÜPER erişim elde edemezsiniz, bu nedenle doğrudan çoğaltma ile uğraşamazsınız (bu bir lütuf mu yoksa lanet mi?). Bununla birlikte, salt okunur bir slave üzerinde şema değişikliklerinizi yapmak için Read Replica Promosyonu kullanabilir ve ardından bu slave'i yeni master'ınız haline getirebilirsiniz. Yukarıda anlattığımla tamamen aynı numara, uygulanması çok daha kolay. Hâlâ kesim konusunda size yardımcı olacak pek bir şey yapmıyorlar. Uygulamanızı yeniden yapılandırmanız ve yeniden başlatmanız gerekiyor.


3
pt-online-schema-change bir ana-bağımlı çoğaltmada bile harika çalışıyor. Bunu, herhangi bir kesinti veya kesinti olmadan 2 replikasyon slave'li üretim ana veritabanımızdaki yoğun okuma 20M + kayıt tablosunda canlı geçiş yapmak için kullandım. Komut dosyasını hazırlamak biraz zaman alıyor ve genellikle aynı SQL'i ancak parça biçiminde (ALTER TABLE yok) çalıştırmak için ham SQL değişikliğini ve sarmalayıcı olarak bir .sh dosyasını içeren bir .sql dosyası oluşturmak zorunda kalıyorum. Pt-online-schema-change ile birden çok komutu dizgeye ekleyerek ve virgülle ayırarak çalıştırabilirsiniz.
Alex Le

-1; Ben eski sürümleri bilmem, ama ben biliyorum indeks oluşturma Bir RC Bu cevap yazılmış anda varolan (bunlar için MySQL 5.6+ eşzamanlı DML bloke etmediğini ve bu cevap süren zaman hangi resmen serbest bırakılmıştı Mayıs 2013'te düzenlendi) çünkü hala ekleri kabul ederken üretim tablolarında çok saatlik indeks oluşturmaları çalıştırmak için buna güvendim. 5.5 ve altında DML'yi engelleyen dizin oluşturma konusunda haklı olsanız da , burada gösterilen saniyenin altındaki gecikme tamamen ikna edici değildir.
Mark Amery

@MarkAmery - engelleme davranışı engelleme davranışıdır ve 400ms sonsuzluktur. Dizin güncellemeleri için MySQL 5.5 blokları. Daha büyük bir test veritabanı oluşturun ve saniyeler, saatler veya günler boyunca engellenecektir. Bu gönderiyi MySQL 5.6 çevrimiçi şema güncellemelerinden önce yazdım, bu yüzden orijinal içeriğim bu gerçeği yansıtmıyor. Gönderiyi yeni mevcut bilgileri yansıtacak şekilde güncelledim.
Dave Dopson

@DaveDopson, yalnızca UPDATE işlemlerinin engellendiğinden% 100 emin misiniz?
toto_tico

Test ettiğim versiyon için durum buydu.
Dave Dopson

67

Bu blog gönderisinin ana hatlarıyla belirtildiği gibi, InnoDB ALTER TABLEmekanizması MySQL 5.6 için tamamen yeniden tasarlandı.

(Bu konuya özel bir genel bakış için, MySQL dokümantasyonu öğleden sonra okumaya değer sağlayabilir.)

Bir tabloya bir dizin eklemek için bir kilidi olmadan üzerine çıkan UPDATE/ INSERTaşağıdaki deyimi biçimi kullanılabilir:

ALTER TABLE my_table ADD INDEX my_table__idx (my_column), ALGORITHM=INPLACE, LOCK=NONE;


16

MySQL 5.6 güncellemesi (Şubat 2013): Artık InnoDB tablolarıyla bile bir dizin oluşturulurken okuma ve yazma işlemleri gerçekleştirebilirsiniz - http://dev.mysql.com/doc/refman/5.6/en/innodb-create-index -overview.html

MySQL 5.6 ve daha yüksek sürümlerde, dizin oluşturulurken veya bırakılırken tablo okuma ve yazma işlemleri için kullanılabilir durumda kalır. CREATE INDEX veya DROP INDEX deyimi, yalnızca tabloya erişen tüm işlemler tamamlandıktan sonra biter, böylece dizinin başlangıç ​​durumu tablonun en son içeriğini yansıtır. Daha önce, bir dizin oluşturulurken veya bırakılırken tabloyu değiştirmek, genellikle tablodaki INSERT, UPDATE veya DELETE deyimini iptal eden bir kilitlenmeyle sonuçlanıyordu.

ve:

MySQL 5.6'da, bu özellik daha genel hale gelir: bir dizin oluşturulurken tabloları okuyabilir ve yazabilirsiniz ve tabloyu kopyalamadan, DML işlemlerini engellemeden veya her ikisini birden yapmadan daha birçok türde ALTER TABLE işlemi gerçekleştirilebilir. Bu nedenle, MySQL 5.6 ve daha yüksek sürümlerde, genellikle bu özellik kümesinden Hızlı Dizin Oluşturma yerine çevrimiçi DDL olarak bahsediyoruz.

dan http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_fast_index_creation


O halde Dave'in analizi nasıl açıklanabilir?
Nikhil Sahu

1
@NikhilSahu Dave açıkça MySQL 5.6 üzerinde değil, bazı eski sürümlerde test ediyor. Dave'in cevabının ilk revizyonunu yayınladığı noktada 5.6'nın henüz yayınlanmadığını unutmayın.
Mark Amery

+1. Analizim MySQL 5.5 üzerindeydi (en son 2013'te mevcuttu). Cevabımı MySQL 5.6'daki yeni yetenekleri yansıtacak şekilde güncelliyorum.
Dave Dopson

3

pt-online-schema-change, geçişin siteyi çökertmeyeceğinden gerçekten emin olmak istiyorsanız, gidilecek yoldur.

Yukarıdaki yorumda yazdığım gibi, üretimde pt-online-schema-change ile ilgili birkaç deneyimim var. 20M + kayıtlardan oluşan ana tablomuz ve bir ana -> 2 salt okunur replikasyon slave'imiz var. Yeni bir sütun eklemekten, karakter kümesini değiştirmekten birkaç dizin eklemeye kadar pt-online-schema-change ile en az bir düzinelerce geçiş yaptım. Göç sırasında da tonlarca trafiğe hizmet ediyoruz ve herhangi bir aksaklık yaşamadık. Elbette, üretime geçmeden önce tüm komut dosyalarını çok ayrıntılı bir şekilde test etmeniz gerekir.

Değişiklikleri 1 betiğe toplu hale getirmeye çalıştım, böylece pt-online-schema-change verileri yalnızca bir kez kopyalamak zorunda kaldı. Verilerinizi kaybedeceğiniz için sütun adını değiştirirken çok dikkatli olun. Bununla birlikte, bir dizin eklemek iyi olmalı.


Niteliksiz tavsiyenize katılmıyorum pt-online-schema-change. Bu harika, ancak MySQL 5.6 + 'nın çevrimiçi DDL yeteneklerinin zaten iyi çalıştığı birçok durumda fazlasıyla kullanılıyor. Aynı zamanda sınırlamaları da vardır (tetikleyicilerle iyi oynamamak gibi) ve bir şema değişikliği devam ederken orijinal tabloya ekleme başına gereken yazma miktarını ikiye katlar. Diskinizi sıradan bir çevrimiçi şema değişikliğinden önemli ölçüde daha fazla vergilendirir ve bu nedenle, şema değişikliğini yalnızca basit şekilde çalıştırmanın işe yarayacağı durumlarda "sitenizi çökertme" potansiyeline sahiptir.
Mark Amery

O zamanki pt-online-schema-change ile ilgili gerçek deneyimime dayanarak yazdım, bu yüzden tavsiyemi neden "niteliksiz" olarak adlandırdığınızdan emin değilim. Şema değişikliklerini yaptığımda herhangi bir anda sitede en az 1000'den fazla ziyaretçimiz oluyordu ve tabii ki disk IO vergilendiriliyordu, ancak sitemiz düşmedi. İyi bir önbelleğe sahip olmak da yardımcı oldu. MySQL 5.6+ çevrimiçi DDL kullanmadım, ancak deneyimlerime göre, pt-online-schema-change işini bizim durumumuzda iyi yaptı.
Alex Le

1
@AlexYe Yikes, "yorum yapmaya yetkili olmayan biri tarafından teslim edilen" anlamından ziyade "çekincesiz" anlamında "niteliksiz" demek istedim - ikinci yorum, ben yorumunuzu görene kadar aklıma gelmedi ve kesinlikle Amaçladığım şey değil! Yani pt-online-schema-change, yararlı bir araç olsa da, sıradan çevrimiçi DDL'nin aynı derecede iyi olduğu ve daha iyi olduğu yerlerde bir avuç dolusu olduğu birçok durum olduğunu söylüyordum , bu yüzden herhangi bir tavsiyenin evrensel olmaktan çok dikkatlice ayrıştırılması gerektiğini söylüyordum.
Mark Amery
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.