Mysql: 1,4 milyar kayıtta endeks yarat


9

1,4 milyar kayıtlı bir masam var. Tablo yapısı aşağıdaki gibidir:

CREATE TABLE text_page (
    text VARCHAR(255),
    page_id INT UNSIGNED
) ENGINE=MYISAM DEFAULT CHARSET=ascii

Gereksinim, sütun üzerinde bir dizin oluşturmaktır text.

Tablo boyutu yaklaşık 34G'dir.

Aşağıdaki ifade ile dizin oluşturmaya çalıştım:

ALTER TABLE text_page ADD KEY ix_text (text)

10 saat bekledikten sonra nihayet bu yaklaşımı bıraktım.

Bu soruna uygulanabilir bir çözüm var mı?

GÜNCELLEME : tablonun güncellenmesi, eklenmesi veya silinmesi olası değildir. Sütunda dizin oluşturmanın textnedeni, bu tür sql sorgusunun sık sık yürütülmesidir:

SELECT page_id FROM text_page WHERE text = ?

GÜNCELLEME : Sorunu tabloyu bölümlere ayırarak çözdüm.

Tablo sütun üzerinde 40 parçaya bölünmüştür text. Ardından tablo üzerinde dizin oluşturma işleminin tamamlanması yaklaşık 1 saat sürer.

Tablo boyutu çok büyüdüğünde MySQL dizin oluşturma çok yavaş görünüyor. Ve bölümleme, tabloyu daha küçük gövdelere indirir.


1
Normal CREATE INDEXifadeyi kullanmanın nesi yanlış ?

Bu sorunun ServerFault üzerinde daha iyi olabileceğini öneririm - bir programlama sorusundan daha çok DB yöneticisi
therefromhere

@Derk: normal CREATE INDEX yaklaşımı çok yavaş. Görevi 1 gün içinde tamamlamak zorundayım.

1
Hmm ... Bunun üstesinden gelebileceğini sanmıyorum. Dizinin oluşturulması, DBMS'nin tüm kayıtları taramasını, "metin" alanlarını toplamasını ve karşılık gelen ağaç düğümlerini / alt ağaçlarını eklemesini / değiştirmesini gerektirir. Ve bu 34G için çok zaman alıyor ...
chiccodoro

DB sunucunuzda ne kadar bellek var? MySQL'i tüm bu belleği kullanacak şekilde yapılandırdınız mı, yoksa kendisini sınırlıyor mu?

Yanıtlar:


4

Sisteminiz sadece göreve uygun olmayabilir mi? MySQL (burada SQL Server) kullanmıyorum, ama 800 milyon giriş tablosunu endekslemenin acısını biliyorum. Temel olarak .... bunun için doğru donanıma ihtiyacınız var (birçok hızlı diskte olduğu gibi). Şimdi neredeyse bir düzine Velociraptors kullanıyorum ve performans harika;)

SQL Server'lar (MS SQL Server olarak değil, SQL kullanan veritabanı sunucuları olarak) disk erişimi ile yaşar ve ölür ve normal diskler daha büyük işlemlerin görevine bağlı değildir.


Şüphem, eğer kayıt sayısı küçükse dizin oluşturma genellikle çok hızlıdır; milyonlar. Ancak sayı milyarlarca olduğunda dizin oluşturma çok yavaşlar. Zaman büyümesinin üstel olduğu anlaşılıyor.

Gerçekten olmamalı. Genel olarak MySQL'in sınırları vardır, ancak bok bir veritabanı değildir ve bu ÇOK kötü olurdu. Endeks üretimi yavaşlar, ancak log (n) ile (n) değil, bu yüzden gerçekten kötü olmamalıdır.
TomTom

4

Metin alanının ilk (örneğin, 10) karakteri üzerinde bir dizin oluşturmak isteyebilirsiniz.

Dokümanlar'dan:

Bir dizin önek uzunluğu belirtmek için col_name (length) sözdizimini kullanarak sütun değerlerinin yalnızca önde gelen bölümünü kullanan dizinler oluşturulabilir:

CREATE INDEX ix_text ON text_page (text(10))

4

Tabloyu bölümlere ayırarak sorunu çözdüm.

Tablo sütun üzerinde 40 parçaya bölünmüştür text. Ardından tablo üzerinde dizin oluşturma işleminin tamamlanması yaklaşık 1 saat sürer.

Tablo boyutu çok büyüdüğünde MySQL dizin oluşturma çok yavaş görünüyor. Ve bölümleme, tabloyu daha küçük gövdelere indirir.


Peki 40 x 1 saat 10 saatten az mı?
symcbean

3

Sort_buffer_size değerini 4GB olarak ayarlayın (veya ne kadar belleğiniz olduğuna bağlı olarak yapabilirsiniz).

Şu anda oluşturma dizini bir sıralama yapıyor ancak 32MB sort_buffer_size'ye sahip olduğunuz için temelde sabit sürücüyü gereksiz yere çöker.


Bu gönderiler hemen hemen sizinle aynı fikirde değiller: xaprb.com/blog/2010/05/09/how-to-tune-mysqls-sort_buffer_size ve daha iyisi ronaldbradford.com/blog/… Bu küresel bir değer değil gibi görünüyor, sorgu başına, yani önerdiğiniz sorgu başına 4 GB. Ayrıca, 256K'yı aştığında, gerçek bellek içi bellek olmak yerine diske eşlenir. Küçük tutarsanız, birden fazla geçiş gerekir, ancak diski önler (değiştirmez).
Ry4an Brase

3

Şunun gibi sorgular yapmanız gerekmiyorsa:

SELECT page_id FROM text_page WHERE text LIKE '?%';

Yeni bir karma sütun oluşturmayı ve sütuna göre tabloyu dizin öneririz. Tablo + dizininin genel boyutu çok daha küçük olabilir.

UPD : Bu arada, 1.4 milyar birincil anahtar tamsayı yaklaşık 6 GB yer kaplıyor, yani dizenin ortalama uzunluğu 30 karakterden az, yani bir önek üzerinde dizin oluşturmak daha fazla tercih edilebilir.

Ayrıca MERGE depolama motoruna da göz atmalısınız .


2

Bunu yapmanın bir yolu, dizin kümesiyle yeni bir tablo oluşturmak ve verileri yeni tabloya kopyalamaktır.

Ayrıca, yeterli sıcaklık alanınız olduğundan emin olun.


1
Bu yaklaşımı denedim. 10 saat sonra% 1'den daha az veri yeni tabloya kopyalandı.

1
Dostum ... 1.4 MİLYON kayıt. Milyon değil, MİLYAR. Bu çok fazla. Ne olursa olsun biraz zaman alacak.

Bu yöntemi kullanmayı seçerseniz, kopyayı daha küçük parçalara bölün. Her kopya için yaklaşık 100-200 milyon deyin.

1
@ ayrıştırılmış, daha küçük parçalara bölmek hiçbir şey yapmaz (aslında, daha az verimli hale getirebilir). @Bryan, 1,4 milyar kayıtla bile 1.000 saat sürmemelidir.

0

Hala bunu en iyi şekilde nasıl yapacağınızı merak ediyorsanız, bir çevrimiçi değiştirme tablosu aracı kullanmanızı öneririm.

İnternette birçoğu var, ünlülerden biri:

Büyük tablolarla aynı sorunlara sahibiz (500mil'den fazla kayıt) ve değiştirme mükemmelleşiyor. Yeni bir tmp tablosu oluşturur, orijinal tabloya tetikleyici ekler (yeni güncelleme / sil / kayıt ekle) ve bu arada tüm kayıtları yeni tabloya kopyalar (yeni yapı ile)

İyi şanslar!

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.