Buat indeks pada tabel produksi MySQL yang besar tanpa penguncian tabel

104

Saya perlu membuat indeks pada tabel MySQL ~ 5 juta baris. Ini adalah tabel produksi, dan saya takut akan semua blok lengkap jika saya menjalankan pernyataan CREATE INDEX ...

Apakah ada cara untuk membuat indeks itu tanpa memblokir sisipan dan seleksi?

Hanya ingin tahu saya belum berhenti, buat indeks, dan mulai ulang sistem saya!

malam hari
sumber
1
pastikan myisam_sort_buffer_size dan myisam_max_sort_file_size Anda cukup besar.
Jon Black

Jawaban:

130

[2017] Pembaruan: MySQL 5.6 memiliki dukungan untuk pembaruan indeks online

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

Di MySQL 5.6 dan yang lebih tinggi, tabel tetap tersedia untuk operasi baca dan tulis saat indeks dibuat atau dihapus. Pernyataan CREATE INDEX atau DROP INDEX hanya selesai setelah semua transaksi yang mengakses tabel selesai, sehingga status awal indeks mencerminkan konten terbaru dari tabel. Sebelumnya, mengubah tabel saat indeks dibuat atau dihapus biasanya mengakibatkan kebuntuan yang membatalkan pernyataan INSERT, UPDATE, atau DELETE pada tabel.

[2015] Tabel yang diperbarui menunjukkan blok menulis di MySQL 5.5

Dari jawaban di atas:

"Jika Anda menggunakan indeks versi lebih besar dari 5.1 yang dibuat saat database sedang online. Jadi, jangan khawatir Anda tidak akan mengganggu penggunaan sistem produksi."

Ini adalah **** FALSE **** (setidaknya untuk tabel MyISAM / InnoDB, yang digunakan oleh 99,999% orang di luar sana. Edisi Clustered berbeda.)

Melakukan operasi UPDATE di atas meja akan DIBLOKIR saat indeks sedang dibuat. MySQL benar-benar bodoh tentang ini (dan beberapa hal lainnya).

Skrip Tes:

(   
  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;'

Server Saya (InnoDB):

Server version: 5.5.25a Source distribution

Output (perhatikan bagaimana operasi ke-6 memblokir ~ 400ms yang diperlukan untuk menyelesaikan pembaruan indeks):

 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

Operasi baca Vs yang tidak memblokir (menukar komentar baris di skrip):

 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

Memperbarui Skema MySQL tanpa waktu henti

Sejauh ini, hanya ada satu metode yang saya ketahui untuk memperbarui skema MySql dan tidak mengalami gangguan ketersediaan. Master melingkar:

  • Master A menjalankan database MySQL Anda
  • Bawa Master B ke dalam layanan dan minta itu mereplikasi penulisan dari Master A (B adalah budak A)
  • Lakukan pembaruan skema pada Master B. Itu akan tertinggal selama peningkatan
  • Biarkan Tuan B menyusul. Invarian: Perubahan skema Anda HARUS dapat memproses perintah yang direplikasi dari skema downversion. Perubahan pengindeksan memenuhi syarat. Penambahan kolom sederhana biasanya memenuhi syarat. Menghapus kolom? mungkin tidak.
  • SECARA ATOMIS menukar semua klien dari Master A ke Master B.Jika Anda ingin aman (percayalah, Anda lakukan), Anda harus memastikan bahwa penulisan terakhir ke A direplikasi ke B SEBELUMB mengambil tulisan pertamanya. Jika Anda mengizinkan penulisan secara bersamaan ke 2+ master, ... Anda lebih memahami replikasi MySQL pada level DEEP atau Anda sedang menuju dunia yang penuh kesulitan. Sakit yang luar biasa. Seperti, apakah Anda memiliki kolom AUTOINCREMENT ??? Anda kacau (kecuali jika Anda menggunakan angka genap pada satu master dan odds di sisi lain). JANGAN percaya replikasi MySQL untuk "melakukan hal yang benar". Ini TIDAK pintar dan tidak akan menyelamatkan Anda. Ini hanya sedikit kurang aman daripada menyalin log transaksi biner dari baris perintah dan memutarnya kembali dengan tangan. Namun, memutuskan semua klien dari master lama dan membaliknya ke master baru dapat dilakukan dalam hitungan detik, jauh lebih cepat daripada menunggu upgrade skema multi-jam.
  • Sekarang Master B adalah master baru Anda. Anda memiliki skema baru. Hidup itu baik. Minum bir; yang terburuk sudah berakhir.
  • Ulangi proses ini dengan Master A, tingkatkan skemanya sehingga dia menjadi master sekunder baru Anda, siap untuk mengambil alih jika master utama Anda (master B sekarang) kehilangan kekuasaan atau mati dan mati pada Anda.

Cara mudah untuk memperbarui skema ini bukan. Bisa diterapkan di lingkungan produksi yang serius; ya itu. Tolong, tolong, tolong, jika ada cara yang lebih mudah untuk menambahkan indeks ke tabel MySQL tanpa memblokir penulisan, beri tahu saya.

Googling membawa saya ke artikel ini yang menjelaskan teknik serupa. Lebih baik lagi, mereka menyarankan minum pada titik yang sama dalam proses (Perhatikan bahwa saya menulis jawaban saya sebelum membaca artikel)!

Pt-online-schema-change Percona

The Artikel saya terkait di atas berbicara tentang alat, pt-secara online-skema-perubahan , yang bekerja sebagai berikut:

  • Buat tabel baru dengan struktur yang sama seperti aslinya.
  • Perbarui skema di tabel baru.
  • Tambahkan pemicu pada tabel asli agar perubahan tetap sinkron dengan salinannya
  • Salin baris dalam kelompok dari tabel asli.
  • Singkirkan tabel asli dan ganti dengan tabel baru.
  • Jatuhkan meja lama.

Saya sendiri belum pernah mencoba alat tersebut. YMMV

RDS

Saya saat ini menggunakan MySQL melalui Amazon's RDS . Ini adalah layanan yang sangat bagus yang membungkus dan mengelola MySQL, memungkinkan Anda menambahkan replika baca baru dengan satu tombol dan secara transparan memutakhirkan basis data di seluruh perangkat keras SKU. Sangat nyaman. Anda tidak mendapatkan akses SUPER ke database, jadi Anda tidak dapat mengacaukan replikasi secara langsung (apakah ini berkah atau kutukan?). Namun, Anda dapat menggunakan Promosi Replika Baca untuk mengubah skema Anda pada budak hanya-baca, lalu promosikan budak tersebut menjadi master baru Anda. Trik yang persis sama seperti yang saya jelaskan di atas, hanya saja jauh lebih mudah untuk dieksekusi. Mereka masih tidak berbuat banyak untuk membantu Anda mengatasi masalah ini. Anda harus mengkonfigurasi ulang dan memulai ulang aplikasi Anda.

Dave Dopson
sumber
3
pt-online-schema-change berfungsi dengan baik bahkan dalam replikasi master-slave. Saya telah menggunakannya untuk melakukan migrasi langsung pada tabel catatan 20 juta + baca yang sibuk di db master produksi kami dengan 2 budak replikasi tanpa cegukan atau waktu henti. Butuh beberapa waktu untuk menyiapkan skrip, dan saya biasanya harus membuat file .sql yang berisi perubahan SQL mentah dan file .sh sebagai pembungkus untuk menjalankan SQL yang sama tetapi dalam format fragmen (tanpa ALTER TABLE). Anda dapat menjalankan beberapa perintah dengan pt-online-schema-change dengan merangkainya dan dipisahkan dengan koma.
Alex Le
-1; Saya tidak tahu tentang versi yang lebih lama, tetapi saya tahu bahwa pembuatan indeks tidak memblokir DML bersamaan di MySQL 5.6+ (yang RC ada pada saat jawaban ini ditulis, dan yang telah dirilis secara resmi saat jawaban ini bertahan diedit pada Mei 2013) karena saya mengandalkan ini untuk menjalankan pembuatan indeks berjam-jam pada tabel produksi sambil tetap menerima sisipan. Dan meskipun Anda mungkin benar tentang pembuatan indeks yang memblokir DML di 5.5 dan di bawahnya, penundaan sub-detik yang ditunjukkan di sini tidak sepenuhnya meyakinkan.
Mark Amery
@MarkAmery - perilaku memblokir adalah perilaku memblokir, dan 400ms adalah selamanya. MySQL 5.5 blok untuk pembaruan indeks. Buat database pengujian yang lebih besar, dan itu akan memblokir selama beberapa detik, jam, atau hari. Saya menulis posting ini sebelum MySQL 5.6 memiliki pembaruan skema online, jadi konten asli saya tidak mencerminkan fakta itu. Saya telah memperbarui posting untuk mencerminkan informasi yang baru tersedia.
Dave Dopson
@DaveDopson, apakah Anda 100% yakin bahwa hanya operasi UPDATE yang diblokir?
toto_tico
Itu adalah kasus untuk versi yang saya uji.
Dave Dopson
67

Seperti yang dijelaskan oleh posting blog ini , ALTER TABLEmekanisme InnoDB telah sepenuhnya didesain ulang untuk MySQL 5.6.

(Untuk gambaran umum eksklusif tentang topik ini, dokumentasi MySQL dapat memberikan bacaan sore hari.)

Untuk menambahkan indeks ke tabel tanpa kunci yang menghasilkan UPDATE/ INSERT, format pernyataan berikut dapat digunakan:

ALTER TABLE my_table ADD INDEX my_table__idx (my_column), ALGORITHM=INPLACE, LOCK=NONE;
Drew
sumber
4
Peringatan: dba.stackexchange.com/questions/138363/…
Alexander Torstling
16

Pembaruan MySQL 5.6 (Februari 2013): Anda sekarang dapat melakukan operasi baca dan tulis saat indeks sedang dibuat bahkan dengan tabel InnoDB - http://dev.mysql.com/doc/refman/5.6/en/innodb-create-index -overview.html

Di MySQL 5.6 dan yang lebih tinggi, tabel tetap tersedia untuk operasi baca dan tulis saat indeks dibuat atau dihapus. Pernyataan CREATE INDEX atau DROP INDEX hanya selesai setelah semua transaksi yang mengakses tabel selesai, sehingga status awal indeks mencerminkan konten terbaru dari tabel. Sebelumnya, mengubah tabel saat indeks dibuat atau dihapus biasanya mengakibatkan kebuntuan yang membatalkan pernyataan INSERT, UPDATE, atau DELETE pada tabel.

dan:

Di MySQL 5.6, fitur ini menjadi lebih umum: Anda dapat membaca dan menulis ke tabel saat indeks dibuat, dan lebih banyak jenis operasi ALTER TABLE dapat dilakukan tanpa menyalin tabel, tanpa memblokir operasi DML, atau keduanya. Jadi di MySQL 5.6 dan yang lebih tinggi, kami biasanya merujuk ke kumpulan fitur ini sebagai DDL online daripada Pembuatan Indeks Cepat.

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

Eric Saboia
sumber
Lalu bagaimana analisis Dave bisa dijelaskan?
Nikhil Sahu
1
@NikhilSahu Dave jelas tidak menguji pada MySQL 5.6, tetapi pada beberapa versi yang lebih lama. Perhatikan bahwa 5.6 belum dirilis pada saat Dave memposting revisi awal jawabannya.
Mark Amery
+1. Analisis saya menggunakan MySQL 5.5 (terbaru yang tersedia pada tahun 2013). Saya memperbarui jawaban saya untuk mencerminkan kemampuan baru di MySQL 5.6.
Dave Dopson
3

pt-online-schema-change adalah cara yang harus dilakukan jika Anda benar-benar ingin memastikan bahwa migrasi tidak akan menurunkan situs.

Seperti yang saya tulis di komentar di atas, saya memiliki beberapa pengalaman dengan pt-online-schema-change dalam produksi. Kami memiliki tabel utama 20M + catatan dan master -> 2 budak replikasi hanya-baca. Saya telah melakukan setidaknya lusinan migrasi dengan pt-online-schema-change dari menambahkan kolom baru, mengubah charset, hingga menambahkan beberapa indeks. Kami juga melayani banyak lalu lintas selama waktu migrasi dan kami tidak mengalami gangguan apa pun. Tentu saja Anda harus menguji semua skrip dengan sangat teliti sebelum menjalankan produksi.

Saya mencoba menggabungkan perubahan menjadi 1 skrip sehingga pt-online-schema-change hanya perlu menyalin data satu kali. Dan berhati-hatilah dengan mengubah nama kolom karena Anda akan kehilangan data Anda. Namun, menambahkan indeks seharusnya baik-baik saja.

Alex Le
sumber
Saya tidak setuju dengan rekomendasi Anda yang tidak memenuhi syarat tentang pt-online-schema-change. Ini bagus, tetapi berlebihan untuk banyak situasi di mana kemampuan DDL online MySQL 5.6 + sudah berfungsi dengan baik. Ini juga memiliki batasan (seperti tidak bermain dengan baik dengan pemicu), dan menggandakan jumlah tulisan yang diperlukan per sisipan ke tabel asli saat perubahan skema sedang berlangsung. Ini akan membebani disk Anda secara signifikan lebih dari perubahan skema online biasa, dan dengan demikian berpotensi untuk "menurunkan situs Anda" dalam situasi di mana hanya menjalankan skema mengubah cara sederhana akan bekerja dengan baik.
Mark Amery
Saya menulis berdasarkan pengalaman saya yang sebenarnya dengan pt-online-schema-change pada saat itu, jadi saya tidak yakin mengapa Anda menyebut rekomendasi saya "tidak memenuhi syarat." Kami memiliki setidaknya 1000+ pengunjung di situs pada saat tertentu ketika saya menjalankan perubahan skema, dan tentu saja, IO disk sedang membebani, tetapi situs kami tidak turun. Memiliki caching yang baik juga membantu. Saya belum menggunakan MySQL 5.6+ DDL online tetapi dari pengalaman saya, pt-online-schema-change melakukan tugasnya dengan baik dalam kasus kami.
Alex Le
1
@AlexYe Astaga, yang saya maksud adalah "tidak memenuhi syarat" dalam arti "tanpa syarat" daripada "disampaikan oleh seseorang yang tidak memenuhi syarat untuk berkomentar" - interpretasi yang terakhir tidak terpikir oleh saya sampai saya melihat komentar Anda dan tentu saja tidak bukan itu yang kuinginkan! yaitu saya katakan bahwa meskipun pt-online-schema-changemerupakan alat yang berguna, ada banyak situasi di mana DDL online biasa sama bagusnya dan sedikit yang lebih baik, jadi setiap rekomendasinya harus diingat dengan hati-hati daripada universal.
Mark Amery