1.000M sıralı MySQL tablosu oluşturma


18

Bu soru gelen yayınlanırsa yığın taşması çoğaltma için yorum, özür de bir öneri göre.

Sorular

Soru 1: Veritabanı tablosunun boyutu büyüdükçe, MySQL'i LOAD DATA INFILE çağrısının hızını artırmak için nasıl ayarlayabilirim?

Soru 2: Farklı CSV dosyaları yüklemek, performansı artırmak veya öldürmek için bir bilgisayar kümesi kullanmak mı istiyorsunuz? (bu, yük verilerini ve toplu ekleri kullanarak yarınki tezgah işaretleme görevim)

Hedef

Görsel arama için farklı özellik dedektörleri ve kümeleme parametreleri kombinasyonlarını deniyoruz, sonuç olarak zamanında ve büyük veritabanları oluşturmamız gerekiyor.

Makine Bilgisi

Makinenin 256 gig ram'si var ve veritabanını dağıtarak oluşturma süresini iyileştirmenin bir yolu varsa aynı miktarda ram ile başka 2 makine daha mevcut mu?

Tablo Şeması

tablo şeması benziyor

+---------------+------------------+------+-----+---------+----------------+
| Field         | Type             | Null | Key | Default | Extra          |
+---------------+------------------+------+-----+---------+----------------+
| match_index   | int(10) unsigned | NO   | PRI | NULL    |                |
| cluster_index | int(10) unsigned | NO   | PRI | NULL    |                |
| id            | int(11)          | NO   | PRI | NULL    | auto_increment |
| tfidf         | float            | NO   |     | 0       |                |
+---------------+------------------+------+-----+---------+----------------+

ile yaratıldı

CREATE TABLE test 
(
  match_index INT UNSIGNED NOT NULL,
  cluster_index INT UNSIGNED NOT NULL, 
  id INT NOT NULL AUTO_INCREMENT,
  tfidf FLOAT NOT NULL DEFAULT 0,
  UNIQUE KEY (id),
  PRIMARY KEY(cluster_index,match_index,id)
)engine=innodb;

Kıyaslama

İlk adım, toplu ekleri ve ikili dosyadan boş bir tabloya yüklemeyi karşılaştırmaktı.

It took:  0:09:12.394571  to do  4,000  inserts with 5,000 rows per insert
It took: 0:03:11.368320 seconds to load 20,000,000 rows from a csv file

Performanstaki fark göz önüne alındığında, ikili bir csv dosyasından veri yükleme ile gitti, önce aşağıdaki çağrıyı kullanarak 100K, 1M, 20M, 200M satırları içeren ikili dosyaları yükledim.

LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test;

200M satır ikili dosyası (~ 3GB csv dosyası) yükünü 2 saat sonra öldürdüm.

Bu yüzden tablo oluşturmak için bir komut dosyası çalıştırdım ve bir ikili dosyadan farklı sayıda satır ekledikten sonra tabloyu bırakın, aşağıdaki grafiğe bakın.

resim açıklamasını buraya girin

İkili dosyadan 1M satır eklemek yaklaşık 7 saniye sürdü. Daha sonra, belirli bir veritabanı boyutunda bir darboğaz olup olmayacağını görmek için bir seferde 1M satırları ekleyerek karşılaştırmaya karar verdim. Veritabanı yaklaşık 59 milyon satıra çarptığında ortalama ekleme süresi yaklaşık 5.000 / saniyeye düştü

resim açıklamasını buraya girin

Genel key_buffer_size = 4294967296 değeri ayarlandığında, daha küçük ikili dosyalar eklemek için hızlar biraz artırıldı. Aşağıdaki grafik farklı satır sayılarının hızlarını göstermektedir

resim açıklamasını buraya girin

Ancak 1M satırları eklemek için performansı iyileştirmedi.

satır sayısı: 1.000.000 süre: 0: 04: 13.761428 kesici uçlar / sn: 3.940

vs boş bir veritabanı için

satır sayısı: 1.000.000 süre: 0: 00: 6.339295 kesici uçlar / sn: 315.492

Güncelleme

Aşağıdaki verileri kullanarak yükleme verisini yapmak - sadece yükle veri komutunu kullanmak yerine

SET autocommit=0;
SET foreign_key_checks=0;
SET unique_checks=0;
LOAD DATA INFILE '/mnt/imagesearch/tests/eggs.csv' INTO TABLE test_ClusterMatches;
SET foreign_key_checks=1;
SET unique_checks=1;
COMMIT;
resim açıklamasını buraya girin

Bu nedenle, oluşturulan veritabanı boyutu açısından oldukça ümit verici görünüyor, ancak diğer ayarlar yük verileri dosya aramasının performansını etkilemiyor gibi görünüyor.

Daha sonra farklı makinelerden birden fazla dosya yüklemeyi denedim ancak veri yükleme komutu, diğer makinelerin zaman aşımına uğramasına neden olan dosyaların büyük boyutu nedeniyle tabloyu kilitliyor

ERROR 1205 (HY000) at line 1: Lock wait timeout exceeded; try restarting transaction

İkili dosyadaki satır sayısını artırma

rows:  10,000,000  seconds rows:  0:01:36.545094  inserts/sec:  103578.541236
rows:  20,000,000  seconds rows:  0:03:14.230782  inserts/sec:  102970.29026
rows:  30,000,000  seconds rows:  0:05:07.792266  inserts/sec:  97468.3359978
rows:  40,000,000  seconds rows:  0:06:53.465898  inserts/sec:  96743.1659866
rows:  50,000,000  seconds rows:  0:08:48.721011  inserts/sec:  94567.8324859
rows:  60,000,000  seconds rows:  0:10:32.888930  inserts/sec:  94803.3646283

Çözüm: Otomatik artış kullanmak yerine kimliği MySQL dışında önceden hesaplama

Masayı oluşturmak

CREATE TABLE test (
  match_index INT UNSIGNED NOT NULL,
  cluster_index INT UNSIGNED NOT NULL, 
  id INT NOT NULL ,
  tfidf FLOAT NOT NULL DEFAULT 0,
  PRIMARY KEY(cluster_index,match_index,id)
)engine=innodb;

SQL ile

LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';"

resim açıklamasını buraya girin

Komut dosyasının dizinleri önceden hesaplamasını sağlamak, veritabanı büyüdükçe performans isabeti kaldırmış gibi görünüyor.

Güncelleme 2 - Bellek tablolarını kullanma

Bellek içi bir tabloyu disk tabanlı tabloya taşıma maliyeti hesaba katılmadan yaklaşık 3 kat daha hızlı.

rows:  0  seconds rows:  0:00:26.661321  inserts/sec:  375075.18851
rows:  10000000  time:  0:00:32.765095  inserts/sec:  305202.83857
rows:  20000000  time:  0:00:38.937946  inserts/sec:  256818.888187
rows:  30000000  time:  0:00:35.170084  inserts/sec:  284332.559456
rows:  40000000  time:  0:00:33.371274  inserts/sec:  299658.922222
rows:  50000000  time:  0:00:39.396904  inserts/sec:  253827.051994
rows:  60000000  time:  0:00:37.719409  inserts/sec:  265115.500617
rows:  70000000  time:  0:00:32.993904  inserts/sec:  303086.291334
rows:  80000000  time:  0:00:33.818471  inserts/sec:  295696.396209
rows:  90000000  time:  0:00:33.534934  inserts/sec:  298196.501594

verileri bir bellek tabanlı tabloya yükleyerek ve sonra parçalar halinde bir disk tabanlı tabloya kopyalayarak 107.356.741 satır sorgu ile kopyalamak için 10 dakika 59.71 sn genel gider vardı

insert into test Select * from test2;

100M satırlarının yüklenmesini yaklaşık 15 dakika yapar, bu da doğrudan disk tabanlı bir tabloya yerleştirmekle aynıdır.


1
Birincil anahtarı sadece iddaha hızlı değiştirmek gerektiğini düşünüyorum. (Bunu aradığınızı düşünmeme rağmen)
DavidEG

Merhaba David, yorum için teşekkürler, ne yazık ki yapmamız gereken anahtarlar yeterince hızlı değil (birincil anahtar seçiminin arkasındaki mantık bu yazıda özetlenmiştir stackoverflow.com/questions/4282526/mysql-group-by- optimizasyonu )
Ben

1
Bu sadece test için mi? MySQL MEMORY motoruna bakmak isteyebilirsiniz: dev.mysql.com/doc/refman/5.0/en/memory-storage-engine.html Bunu bir mimari olarak dağıtmayı planlıyorsanız nasıl planlayacağınızı merak ediyorum hatalardan kurtulmak, MapReduce / Hadoop tarafından daha iyi ele alınacak bir şey gibi görünüyor.
polinom

Merhaba polinom, bahşiş için teşekkürler, şu anda sadece farklı ölçeklerde farklı özellik dedektörlerini test ediyoruz, veritabanı oluşturulduktan sonra çok fazla değişmeyecek (zaten mevcut spesifikasyonda)
Ben

Yanıtlar:


4

İyi soru - iyi açıkladı.

MySQL'i LOAD DATA INFILE çağrısının hızını artırmak için nasıl ayarlayabilirim?

Anahtar arabelleği için zaten yüksek bir (ish) ayarınız var - ama yeterli mi? Bu 64-bit bir kurulum (varsa o zaman yapmanız gereken ilk şey yükseltme) ve MSNT üzerinde çalışmıyor varsayalım. Birkaç test yaptıktan sonra mysqltuner.pl çıktısına bir göz atın.

Önbelleği en iyi etkiyi elde etmek için, giriş verilerini toplu olarak / ön sıralamada faydalar bulabilirsiniz ('sort' komutunun en son sürümlerinde büyük veri kümelerini sıralamak için çok fazla işlevsellik vardır). Ayrıca kimlik numaralarını MySQL dışında oluşturursanız, daha verimli olabilir.

farklı csv dosyaları yüklemek için bir bilgisayar kümesi kullanıyor

Çıktının tek bir tablo gibi davranmasını istediğinizi varsayarsak, elde edeceğiniz tek fayda, daha fazla veritabanı gerektirmeyen kimlikleri sıralama ve oluşturma işini dağıtarak elde etmektir. Bir veritabanı kümesi kullanarak OTOH, çekişme ile ilgili sorunlar alacaksınız (performans sorunları dışında görmemeniz gerekir).

Verileri parçalayabilir ve elde edilen veri kümelerini bağımsız olarak işleyebiliyorsanız, evet, performans avantajları elde edersiniz - ancak bu, her düğümü ayarlama ihtiyacını ortadan kaldırmaz.

Sort_buffer_size için en az 4 Gb'niz olduğunu kontrol edin.

Bunun ötesinde, performans üzerindeki sınırlayıcı faktör tamamen disk G / Ç ile ilgilidir. Bunu ele almanın birçok yolu vardır - ancak en iyi performans için muhtemelen SSD'lerde yansıtılmış bir dizi çizgili veri kümesini düşünmelisiniz.


1
  • Sınırlayıcı faktörünüzü düşünün. Neredeyse kesinlikle tek iş parçacıklı CPU işleme.
  • load data...Eklemeden daha hızlı olduğunu zaten belirlediniz , bu yüzden kullanın.
  • Gerçekten büyük dosyaların (satır numarasına göre) işleri çok yavaşlattığını zaten belirlediniz; onları parçalara ayırmak istiyorsun.
  • Çakışan olmayan birincil anahtarlar kullanarak, en az N * CPU setini sıralayın, bir milyondan fazla satır kullanmayın ... muhtemelen daha az (kıyaslama).
  • Her dosyada birincil anahtarların ardışık bloklarını kullanın.

Gerçekten şık olmak istiyorsanız, tek bir dosyayı adlandırılmış kanallar koleksiyonuna beslemek ve ekleme örneklerini yönetmek için çok iş parçacıklı bir program oluşturabilirsiniz.

Özetle, iş yükünüzü MySQL olarak ayarladığınız için MySQL'i bu kadar ayarlamıyorsunuz.


-1

Tam sözdizimini hatırlamıyorum ama inno db ise yabancı anahtar kontrolünü kapatabilirsiniz.

Ayrıca içe aktarmadan sonra dizini oluşturabilirsiniz, bu gerçekten bir performans kazancı olabilir.


Dizin yeniden oluşturmanın ertelenmesi, yalnızca tabloda zaten bulunan satır sayısının eklediğiniz satır sayısından önemli ölçüde az olduğu performansı artırır.
symcbean
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.