Merhaba arkadaşlar, bugün sizlere özellikle milyonlarca satırlık CSV veya metin dosyalarını MySQL veritabanınıza nasıl hızlı ve verimli bir şekilde yükleyebileceğinizi anlatacağım. INSERT INTO ... VALUES komutlarıyla tek tek satır eklemek büyük veri setlerinde saatler sürebilir. Benim sunucularda genelde kullandığım yöntem, MySQL'in yerleşik LOAD DATA INFILE komutudur. Bu rehberde hem temel kullanımını hem de performansını nasıl uçurabileceğimizi göreceğiz.
LOAD DATA INFILE Nedir ve Neden Kullanmalıyım?
LOAD DATA INFILE, MySQL'in bir metin dosyasındaki satırları doğrudan bir tabloya yüklemek için optimize edilmiş bir komutudur. Normal INSERT işlemlerine göre 20 kat veya daha fazla hız farkı yaratabilir. Özellikle log dosyalarını, dış sistemlerden aldığınız CSV raporlarını veya yedekten dönüş yaparken bu komut hayat kurtarıcıdır.
Temel Kullanım ve Sözdizimi
En basit haliyle komut şöyle kullanılır. Diyelim ki /tmp/veriler.csv dosyamız var ve `kullanicilar` tablomuza yükleyeceğiz.
Şimdi bu komutu parçalayalım:
- INFILE 'dosya_yolu': Yüklenecek dosyanın tam yolu. Bu dosyanın MySQL sunucusu üzerinde olması ve MySQL kullanıcısının bu dosyayı okuma iznine sahip olması gerekir.
- INTO TABLE tablo_adi: Verilerin ekleneceği hedef tablo.
- FIELDS TERMINATED BY ',': Sütunların dosyada hangi karakterle ayrıldığını belirtir (CSV için genelde virgül).
- ENCLOSED BY '"': Metin alanlarının hangi karakterle çevrili olduğunu belirtir (genelde çift tırnak).
- LINES TERMINATED BY '\n': Satırların nasıl bittiğini belirtir (Linux/Unix için \n).
- IGNORE 1 ROWS: Dosyanın ilk satırı başlık (header) satırı ise onu atlamak için kullanılır.
Güvenlik ve Dosya Konumu Dikkati
Şu ayara çok dikkat etmelisiniz: Varsayılan olarak MySQL, secure_file_priv sistem değişkeni ile hangi dizinlerden dosya yüklenebileceğini kısıtlar. Bu değeri görmek için aşağıdaki komutu çalıştırın:
Eğer değer NULL ise, LOAD DATA INFILE kullanılamaz. Eğer bir dizin belirtiyorsa (örn: /var/lib/mysql-files/), yükleyeceğiniz dosyayı mutlaka o dizine kopyalamanız gerekir. Aksi takdirde "ERROR 1290" hatası alırsınız.
Performans Optimizasyon İpuçları
Büyük dosyaları yüklerken işlemi daha da hızlandırmak için birkaç püf noktası paylaşayım.
1. İndeksleri Geçici Olarak Kaldırın: Tablonuzda çok sayıda INDEX, özellikle de FULLTEXT index varsa, veri yüklemeden önce bunları DROP edip, yükleme tamamlandıktan sonra tekrar CREATE edin. Her satır eklemede indeks güncellemesi büyük yük getirir.
2. Toplu İşlem (Batch) Boyutunu Ayarlayın: Aşağıdaki sistem değişkenlerini geçici olarak artırabilirsiniz. Bu işlemler sunucu RAM kullanımını artırabilir, dikkatli olun.
3. Otomatik Commit'i Kapatın: İşlemi tek bir büyük transaction içinde yapmak loglama yükünü azaltır.
Gelişmiş Kullanım: Sütun Eşleme ve Veri Dönüşümü
Dosyanızdaki sütun sırası tablonuzdaki sütun sırasından farklıysa veya bazı sütunları atlamak/hesaplamak istiyorsanız, sütun eşlemesi yapabilirsiniz. Örneğin, dosyada 3 sütun var (isim, yas, sehir) ama tabloda 4 sütun var (id, isim, yas, eklenme_tarihi). `id` otomatik artan, `eklenme_tarihi` de şu anki zaman olacak.
Son Kontroller ve Hata Ayıklama
İşlem bittiğinde kaç satırın eklendiğini, kaç satırın uyarı ile eklendiğini görmek için aşağıdaki komutları kullanabilirsiniz:
Eğer "Warnings" çıkarsa, genellikle veri tipi uyuşmazlığı (string'in sayıya dönüştürülmesi gibi) veya TRUNCATE (veri kesilmesi) olmuş demektir. Bu uyarıları mutlaka kontrol edin.
Umarım bu detaylı rehber, bir sonraki büyük veri yükleme işleminizde size saatler kazandırır. Benzer işlemleri yaparken genelde indeksleri kaldırıp, transaction içinde yüklemeyi tercih ediyorum. Siz bu konfigürasyonu kendi sunucularınızda nasıl yapıyorsunuz? Farklı bir yöntem veya taktiğiniz var mı? Ya da takıldığınız bir nokta olursa aşağıya yazmaktan çekinmeyin, beraber çözelim.
LOAD DATA INFILE, MySQL'in bir metin dosyasındaki satırları doğrudan bir tabloya yüklemek için optimize edilmiş bir komutudur. Normal INSERT işlemlerine göre 20 kat veya daha fazla hız farkı yaratabilir. Özellikle log dosyalarını, dış sistemlerden aldığınız CSV raporlarını veya yedekten dönüş yaparken bu komut hayat kurtarıcıdır.
En basit haliyle komut şöyle kullanılır. Diyelim ki /tmp/veriler.csv dosyamız var ve `kullanicilar` tablomuza yükleyeceğiz.
SQL:
LOAD DATA INFILE '/tmp/veriler.csv'
INTO TABLE kullanicilar
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 ROWS;
Şimdi bu komutu parçalayalım:
- INFILE 'dosya_yolu': Yüklenecek dosyanın tam yolu. Bu dosyanın MySQL sunucusu üzerinde olması ve MySQL kullanıcısının bu dosyayı okuma iznine sahip olması gerekir.
- INTO TABLE tablo_adi: Verilerin ekleneceği hedef tablo.
- FIELDS TERMINATED BY ',': Sütunların dosyada hangi karakterle ayrıldığını belirtir (CSV için genelde virgül).
- ENCLOSED BY '"': Metin alanlarının hangi karakterle çevrili olduğunu belirtir (genelde çift tırnak).
- LINES TERMINATED BY '\n': Satırların nasıl bittiğini belirtir (Linux/Unix için \n).
- IGNORE 1 ROWS: Dosyanın ilk satırı başlık (header) satırı ise onu atlamak için kullanılır.
Şu ayara çok dikkat etmelisiniz: Varsayılan olarak MySQL, secure_file_priv sistem değişkeni ile hangi dizinlerden dosya yüklenebileceğini kısıtlar. Bu değeri görmek için aşağıdaki komutu çalıştırın:
SQL:
SHOW VARIABLES LIKE 'secure_file_priv';
Eğer değer NULL ise, LOAD DATA INFILE kullanılamaz. Eğer bir dizin belirtiyorsa (örn: /var/lib/mysql-files/), yükleyeceğiniz dosyayı mutlaka o dizine kopyalamanız gerekir. Aksi takdirde "ERROR 1290" hatası alırsınız.
Büyük dosyaları yüklerken işlemi daha da hızlandırmak için birkaç püf noktası paylaşayım.
1. İndeksleri Geçici Olarak Kaldırın: Tablonuzda çok sayıda INDEX, özellikle de FULLTEXT index varsa, veri yüklemeden önce bunları DROP edip, yükleme tamamlandıktan sonra tekrar CREATE edin. Her satır eklemede indeks güncellemesi büyük yük getirir.
2. Toplu İşlem (Batch) Boyutunu Ayarlayın: Aşağıdaki sistem değişkenlerini geçici olarak artırabilirsiniz. Bu işlemler sunucu RAM kullanımını artırabilir, dikkatli olun.
SQL:
SET GLOBAL bulk_insert_buffer_size = 1024 1024 256; -- 256MB
SET GLOBAL max_allowed_packet = 1024 1024 64; -- 64MB
3. Otomatik Commit'i Kapatın: İşlemi tek bir büyük transaction içinde yapmak loglama yükünü azaltır.
SQL:
SET autocommit=0;
SET unique_checks=0;
SET foreign_key_checks=0;
-- LOAD DATA INFILE komutunuz buraya gelir
SET foreign_key_checks=1;
SET unique_checks=1;
COMMIT;
SET autocommit=1;
Dosyanızdaki sütun sırası tablonuzdaki sütun sırasından farklıysa veya bazı sütunları atlamak/hesaplamak istiyorsanız, sütun eşlemesi yapabilirsiniz. Örneğin, dosyada 3 sütun var (isim, yas, sehir) ama tabloda 4 sütun var (id, isim, yas, eklenme_tarihi). `id` otomatik artan, `eklenme_tarihi` de şu anki zaman olacak.
SQL:
LOAD DATA INFILE '/tmp/veriler.csv'
INTO TABLE kullanicilar
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
IGNORE 1 ROWS
(isim, yas, sehir) -- Dosyadaki sütunları sırasıyla belirt
SET eklenme_tarihi = NOW(); -- Ekstra bir sütuna değer ataması yap
İşlem bittiğinde kaç satırın eklendiğini, kaç satırın uyarı ile eklendiğini görmek için aşağıdaki komutları kullanabilirsiniz:
SQL:
SHOW WARNINGS;
SELECT ROW_COUNT();
Eğer "Warnings" çıkarsa, genellikle veri tipi uyuşmazlığı (string'in sayıya dönüştürülmesi gibi) veya TRUNCATE (veri kesilmesi) olmuş demektir. Bu uyarıları mutlaka kontrol edin.
Umarım bu detaylı rehber, bir sonraki büyük veri yükleme işleminizde size saatler kazandırır. Benzer işlemleri yaparken genelde indeksleri kaldırıp, transaction içinde yüklemeyi tercih ediyorum. Siz bu konfigürasyonu kendi sunucularınızda nasıl yapıyorsunuz? Farklı bir yöntem veya taktiğiniz var mı? Ya da takıldığınız bir nokta olursa aşağıya yazmaktan çekinmeyin, beraber çözelim.