MySQL'de 300 milyon kaydın fiziksel olarak silinmesinin hikayesi

Giriş

Merhaba. Ben NingenMe, web geliştiricisiyim.

Başlıktan da anlaşılacağı gibi benim hikayem MySQL'de 300 milyon kaydın fiziksel olarak silinmesinin hikayesi.

Bu konuyla ilgilenmeye başladım ve bir hatırlatma (talimat) yapmaya karar verdim.

Ana Sayfa - Uyarı

Kullandığım ve bakımını yaptığım toplu sunucunun, geçen ayın verilerini MySQL'den günde bir kez toplayan düzenli bir süreci var.

Genellikle bu işlem yaklaşık 1 saatte tamamlanıyor ama bu sefer 7-8 saatte tamamlanmadı ve uyarı da bir türlü ortaya çıkmadı...

bir sebep bulmak

İşlemi yeniden başlatmayı ve günlüklere bakmayı denedim ancak yanlış bir şey görmedim.
Sorgu doğru şekilde dizine eklendi. Ancak neyin yanlış gittiğini düşündüğümde veritabanı boyutunun oldukça büyük olduğunu fark ettim.

hoge_table | 350'000'000 |

350 milyon kayıt. İndeksleme doğru çalışıyor gibi görünüyordu, ancak çok yavaştı.

Aylık gerekli veri toplama miktarı yaklaşık 12 kayıttı. Select komutunun uzun sürdüğü ve işlemin uzun süre yürütülmediği görülüyor.

DB

Bu aslında her gün yaklaşık 400 girişle büyüyen bir tablodur. Veritabanının yalnızca son aya ait veri toplaması gerekiyordu, dolayısıyla tam olarak bu miktarda veriye dayanması bekleniyordu ancak maalesef döndürme işlemine yer verilmedi.

Bu veritabanı benim tarafımdan geliştirilmemiştir. Bunu başka bir geliştiriciden devraldım, bu yüzden hala teknik bir borç gibi hissettim.

Günlük olarak eklenen veri hacminin büyüdüğü ve sonunda sınırına ulaştığı bir nokta geldi. Bu kadar büyük miktarda veriyle çalışırken bunları ayırmanın gerekli olacağı varsayılıyor ancak bu ne yazık ki yapılmadı.

Ve sonra harekete geçtim.

Düzeltme

Mantığı değiştirmek yerine veritabanının boyutunu küçültmek ve işleme süresini kısaltmak daha mantıklıydı.

300 milyon kaydı silerseniz durum önemli ölçüde değişecektir, ben de bunu yapmaya karar verdim... Eh, bunun kesinlikle işe yarayacağını düşündüm.

Eylem 1

Güvenilir bir yedekleme hazırladıktan sonra nihayet istek göndermeye başladım.

''Bir istek gönderiyorum''

DELETE FROM hoge_table WHERE create_time <= 'YYYY-MM-DD HH:MM:SS';

"..."

"..."

“Hımm... Cevap yok. Belki süreç uzun sürüyor?” — Düşündüm ama her ihtimale karşı grafanaya baktım ve disk yükünün çok hızlı arttığını gördüm.
"Tehlikeli" diye tekrar düşündüm ve isteği hemen durdurdum.

Eylem 2

Her şeyi analiz ettikten sonra veri hacminin her şeyi bir kerede silemeyecek kadar büyük olduğunu fark ettim.

Yaklaşık 1 kaydı silebilecek bir script yazmaya karar verdim ve onu başlattım.

''Senaryoyu ben uyguluyorum''

“Şimdi bu kesinlikle işe yarayacak” diye düşündüm.

Eylem 3

İkinci yöntem işe yaradı ancak çok emek yoğun olduğu ortaya çıktı.
Her şeyi gereksiz sinirlere kapılmadan dikkatli bir şekilde yapmak yaklaşık iki hafta sürer. Ancak yine de bu senaryo hizmet gereksinimlerini karşılamadığından bundan uzaklaşmak zorunda kaldık.

İşte yapmaya karar verdiğim şey:

Tabloyu kopyalayın ve yeniden adlandırın

Önceki adımdan itibaren, bu kadar büyük miktarda veriyi silmenin aynı derecede büyük bir yük oluşturduğunu fark ettim. Bu yüzden insert kullanarak sıfırdan yeni bir tablo oluşturmaya ve sileceğim verileri bu tabloya taşımaya karar verdim.

| hoge_table     | 350'000'000|
| tmp_hoge_table |  50'000'000|

Yeni tabloyu yukarıdakiyle aynı boyutta yaparsanız veri işleme hızı da 1/7 oranında artacaktır.

Tabloyu oluşturup adını değiştirdikten sonra ana tablo olarak kullanmaya başladım. Şimdi 300 milyon kayıt içeren tabloyu bırakırsam her şey yoluna girecek.
Kesmenin veya bırakmanın silmeye göre daha az yük oluşturduğunu öğrendim ve bu yöntemi kullanmaya karar verdim.

Performans

''Bir istek gönderiyorum''

INSERT INTO tmp_hoge_table SELECT FROM hoge_table create_time > 'YYYY-MM-DD HH:MM:SS';

"..."
"..."
"Ee...?"

Eylem 4

Önceki fikrin işe yarayacağını düşünmüştüm ancak ekleme isteğini gönderdikten sonra birden fazla hata ortaya çıktı. MySQL affedici değildir.

Zaten o kadar yorulmuştum ki artık bunu yapmak istemediğimi düşünmeye başladım.

Oturdum, düşündüm ve bir defalığına çok fazla ekleme sorgusu olabileceğini fark ettim...
Veritabanının 1 günde işlemesi gereken veri miktarı için ekleme isteği göndermeyi denedim. Olmuş!

Bundan sonra aynı miktarda veri için istek göndermeye devam ediyoruz. Bir aylık veriyi kaldırmamız gerektiğinden bu işlemi yaklaşık 35 kez tekrarlıyoruz.

Bir tabloyu yeniden adlandırma

Burada şans benden yanaydı: her şey yolunda gitti.

Uyarı kayboldu

Toplu işlem hızı arttı.

Daha önce bu işlem yaklaşık bir saat sürüyordu, şimdi ise yaklaşık 2 dakika sürüyor.

Tüm sorunların çözüldüğünden emin olduktan sonra 300 milyon kayıt bıraktım. Masayı sildim ve yeniden doğduğumu hissettim.

Özet

Toplu işlemede rotasyon işleminin eksik olduğunu fark ettim ve asıl sorun da buydu. Bu tür mimari hatalar zaman kaybına neden olur.

Veritabanından kayıtları silerken veri çoğaltma sırasındaki yükü düşünüyor musunuz? MySQL'e aşırı yükleme yapmayalım.

Veritabanlarına hakim olanlar kesinlikle böyle bir sorunla karşılaşmayacaktır. Geri kalanınız için bu makalenin faydalı olduğunu umuyorum.

Okuduğunuz için teşekkürler!

Bu makaleyi beğenip beğenmediğinizi, çevirisinin anlaşılır olup olmadığını, işinize yarayıp yaramadığını bize söylerseniz çok seviniriz.

Kaynak: habr.com

Yorum ekle