35 milyon satır için etkili mysql tablo / dizin tasarımı + tablo, 200'den fazla karşılık gelen sütun (çift), herhangi bir kombinasyonu sorgulanabilir


17

Aşağıdaki durum için tablo / dizin tasarımı konusunda tavsiye arıyorum:

Bileşik birincil anahtar (varlık kimliği (int), tarih (tarih)) ile büyük bir tablo (hisse senedi fiyat geçmişi verileri, InnoDB, 35 milyon satır ve büyüyen) var. fiyatlandırma bilgilerine ek olarak, her bir kayda karşılık gelmesi gereken 200 çift değer var.

CREATE TABLE `mytable` (
`assetid` int(11) NOT NULL,
`date` date NOT NULL,
`close` double NOT NULL,
`f1` double DEFAULT NULL,   
`f2` double DEFAULT NULL,
`f3` double DEFAULT NULL,   
`f4` double DEFAULT NULL,
 ... skip a few 
`f200` double DEFAULT NULL, 
PRIMARY KEY (`assetid`, `date`)) ENGINE=`InnoDB` DEFAULT CHARACTER SET latin1 COLLATE
    latin1_swedish_ci ROW_FORMAT=COMPACT CHECKSUM=0 DELAY_KEY_WRITE=0 
    PARTITION BY RANGE COLUMNS(`date`) PARTITIONS 51;

Başlangıçta güncelleme ve alma kolaylığı için 200 çift sütun doğrudan bu tabloda saklanan ve bu tablo üzerinde yapılan tek sorgu varlık ve tarih (bu dini karşı bu tabloya karşı herhangi bir sorguda dahil olduğu gibi) iyi çalışıyor olmuştu ) ve 200 çift sütun yalnızca okundu. Veritabanı boyutum yaklaşık 45 Gig idi

Ancak, şimdi ben bu tabloyu bu 200 sütun (f1, f2, ... f200 adlı) herhangi bir kombinasyonu ile sorgulamak gerekir gerekir gereksinimi var:

select from mytable 
where assetid in (1,2,3,4,5,6,7,....)
and date > '2010-1-1' and date < '2013-4-5'
and f1 > -0.23 and f1 < 0.9
and f117 > 0.012 and f117 < .877
etc,etc

tarihsel olarak daha önce bu kadar büyük miktarda veri ile uğraşmak zorunda kalmadım, bu yüzden ilk içgüdüm, bu 200 sütunun her birinde indekslere ihtiyaç duyulduğu ya da büyük tablo taramaları vb. birincil anahtar, değer ve değerleri dizin 200 sütunların her biri için bir tablo gerekli. Ben de bununla gittim.

CREATE TABLE `f1` (
`assetid` int(11) NOT NULL DEFAULT '0',
`date` date NOT NULL DEFAULT '0000-00-00',
`value` double NOT NULL DEFAULT '0',
PRIMARY KEY (`assetid`, `date`),
INDEX `val` (`value`)
) ENGINE=`InnoDB` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ROW_FORMAT=COMPACT CHECKSUM=0 DELAY_KEY_WRITE=0;

i doldurdu ve tüm 200 tablolar dizin. Düzenli olarak varlık kimliği ve tarih aralığı üzerinden sorgulandığı ve 200 sütunun tümü seçildiği için ana tabloyu 200 sütunun tümüyle sağlam bıraktım. Ben bu sütunları okuma amacıyla üst tabloda (unindexed) bırakmanın ve daha sonra ek olarak kendi tablolarında (birleştirme filtrelemesi için) dizine eklenmesinin en yüksek performans olacağını düşündüm. Sorgunun yeni formunu açıkladım

select count(p.assetid) as total 
from mytable p 
inner join f1 f1 on f1.assetid = p.assetid and f1.date = p.date
inner join f2 f2 on f2.assetid = p.assetid and f2.date = p.date 
where p.assetid in(1,2,3,4,5,6,7)
and p.date >= '2011-01-01' and p.date < '2013-03-14' 
and(f1.value >= 0.96 and f1.value <= 0.97 and f2.value >= 0.96 and f2.value <= 0.97) 

Gerçekten istenen sonucum elde edildi, açıklamak bana taranan satırların bu sorgu için çok daha küçük olduğunu gösterir. Ancak bazı istenmeyen yan etkileri ile yara.

1) Veritabanım 45 Gig'den 110 Gig'e gitti. Artık db'yi RAM'de tutamıyorum. (Ancak yolda 256Gig RAM var)

2) Yeni verilerin gece eklenmesi artık bir kez yerine 200 kez yapılmalıdır.

3) yeni 200 masanın bakımı / dolandırmak sadece 1 masanın 200 kat daha uzun sürer. Bir gecede tamamlanamaz.

4) f1 vb. Tablolara karşı yapılan sorguların mutlaka performans göstermesi gerekmez. Örneğin:

 select min(value) from f1 
 where assetid in (1,2,3,4,5,6,7) 
 and date >= '2013-3-18' and date < '2013-3-19'

Yukarıdaki sorgu, açıklamanın <1000 satıra baktığını gösterirken, tamamlanması 30+ saniye sürebilir. Bunun, dizinlerin belleğe sığmayacak kadar büyük olması nedeniyle olduğunu varsayalım.

Bu çok kötü bir haber olduğundan, daha fazla baktım ve bölümleme buldum. Ana tabloya, her 3 ayda bir bölümlenmiş bölümler uyguladım. Aylık bana mantıklı geldi ama 120'den fazla bölüm aldığınızda performansın düştüğünü okudum. üç ayda bir bölümleme yapmak önümüzdeki 20 yıl boyunca beni bunun altında bırakacak. her bölüm 2 Gig altında biraz. bölümleri açıklamak koştu ve her şey düzgün budama gibi görünüyor, bu yüzden bölümleme en azından analiz / optimize / onarım amaçlı en iyi adım olduğunu hissediyorum.

Bu yazı ile çok zaman geçirdim

http://ftp.nchu.edu.tw/MySQL/tech-resources/articles/testing-partitions-large-db.html

Şu anda benim tablo hala üzerinde birincil anahtar ile bölümlenmiştir. Makale, birincil anahtarların bölümlenmiş bir tabloyu yavaşlatabileceğinden bahseder, ancak bunu işleyebilecek bir makineniz varsa, bölümlenmiş tablodaki birincil anahtarlar daha hızlı olacaktır. Yolda büyük bir makinem olduğunu bilerek (256 G RAM), tuşları açık bıraktım.

gördüğüm gibi, işte benim seçeneklerim

seçenek 1

1) ekstra 200 tabloyu kaldırın ve sorgunun f1, f2 vb değerlerini bulmak için tablo taramaları yapmasına izin verin. benzersiz olmayan dizinler aslında düzgün bir şekilde bölümlenmiş bir tabloda performansa zarar verebilir. kullanıcı sorguyu çalıştırmadan önce bir açıklama çalıştırın ve taranan satır sayısı tanımladığım bir eşiğin üzerindeyse bunları reddet. Kendimi dev veritabanının acılarından kurtarıyorum. Heck, hepsi yakında hafızada olacak.

alt sorusu:

uygun bir bölüm şeması seçmişim gibi görünüyor mu?

seçenek 2

Tüm 200 tabloları aynı 3 aylık şemayı kullanarak bölün. daha küçük satır taramalarının keyfini çıkarın ve kullanıcıların daha büyük sorgular çalıştırmasına izin verin. şimdi en azından bölümlere ayrıldığına göre bakım amacıyla bir seferde 1 bölüm yönetebilirim. Heck, hepsi yakında hafızada olacak. Bunları her gece güncellemek için etkili bir yol geliştirin.

alt sorusu:

Bu f1, f2, f3, f4 ... tablolarında birincil anahtar dizinlerinden kaçınmamın bir nedeni var mı? bana karşı sezgisel görünüyor ama bu boyuttaki veri kümelerine alışkın değilim. Ben varsayıyorum bir demet veritabanını küçültecek

Seçenek 3

Bu alanı geri kazanmak için ana tabloya f1, f2, f3 sütunlarını bırakın. 200 özelliği okumak gerekiyorsa 200 birleşimler yapmak, belki sesler kadar yavaş olmayacak.

Seçenek 4

Hepinizin bunu yapılandırmak için şimdiye kadar düşündüğümden daha iyi bir yolu var.

* NOT: Yakında her bir öğeye bu çift değerlerden başka bir 50-100 ekleyeceğim, bu yüzden geleceğini bilerek tasarlamam gerekiyor.

Her türlü yardım için teşekkürler

Güncelleme # 1 - 3/24/2013

Aşağıda aldığım yorumlarda önerilen fikirle gittim ve aşağıdaki kurulumla yeni bir tablo oluşturdum:

create table 'features'{
  assetid int,
  date    date,
  feature varchar(4),
  value   double
}

Tabloyu 3 ay arayla ayırdım.

Daha önceki 200 tabloyu havaya uçurdum, böylece veritabanım tekrar 45 Gig'e düştü ve bu yeni tabloyu doldurmaya başladı. Bir buçuk gün sonra, tamamlandı ve veritabanım şimdi tombul 220 konserde oturuyor !

Bu 200 değeri ana tablodan kaldırma olasılığına izin verir, çünkü onları bir birleştirmeden alabilirim, ama bu gerçekten sadece bana 25 Gigs ya da öylesine geri verirdi

Varlık, tarih, özellik ve değer üzerinde bir dizin üzerinde birincil bir anahtar oluşturmak istedi ve 9 saat chugging sonra gerçekten bir göçük yapmamıştı ve donmuş gibi görünüyordu bu yüzden bu kısmı öldürdü.

Birkaç bölüm yeniden inşa etti ama çok / herhangi bir alan geri almak gibi görünmüyordu.

Yani bu çözüm muhtemelen ideal olmayacak gibi görünüyor. Satırlar merak ettiğim sütunlardan çok daha fazla yer kaplıyor mu, bu yüzden bu çözüm çok daha fazla yer kaplayabilir mi?

Bu yazıyla karşılaştım:

http://www.chrismoos.com/2010/01/31/mysql-partitioning-tables-with-millions-of-rows

bana bir fikir verdi. Diyor ki:

İlk başta, RANGE bölümünü tarihe göre bölümlendirmeyi düşündüm ve tarihi sorgularımda kullanırken, bir sorgunun çok geniş bir tarih aralığına sahip olması çok yaygın ve bu da tüm bölümleri kolayca kapsayabileceği anlamına geliyor.

Şimdi tarihe göre bölümleme de yapıyorum, ancak bölümlememin etkinliğini azaltacak geniş tarih aralığına göre aramalara da izin vereceğim. Arama yaparken her zaman bir tarih aralığına sahip olacağım, ancak her zaman varlıkların bir listesi de olacak. Belki de benim çözüm ben tipik olarak aranan varlık kimliği aralıkları (ki ben gelebilir, standart listeler, S & P 500, Russell 2000, vb vardır) tanımlamak varlık ve tarihe göre bölümleme olmalıdır. Bu şekilde neredeyse hiçbir zaman tüm veri setine bakmazdım.

Sonra tekrar, ben birincil varlık ve zaten tarih anahtarlı, bu yüzden belki de çok yardımcı olmaz.

Daha fazla düşünce / yorum takdir edilecektir.


2
Neden 200 masaya ihtiyacın olduğunu anlayamıyorum. İle tek tablo (value_name varchar(20), value double)mağaza her şeyi mümkün olacaktır ( value_namevarlık f1, f2...)
a_horse_with_no_name

Teşekkürler. onları ayrı ayrı koymak bir masada 50 endeks sınırı tarafından almak oldu. Onları 5 tabloya, her biri 40 değerlere koymayı düşünmüştüm, ancak her biri için bir günde 17000 kadar kayıt ekliyorum ve 40 endeksli bir tabloda ne gibi bir performansın olacağını biliyordum. varlıkların her kombinasyonunun, tarihin kendi f1, f2 ... değerlerini aldığını unutmayın. Birincil anahtar varlık kimliği, tarih, belki dizini açık (değer_adı, değer) içeren (öğe kimliği, tarih, değer_adı, değer) içeren tek bir tablo mu öneriyorsunuz? bu tablonun 35 mil * 200 = 7 milyar sıraları olurdu, ama belki de bölümlenmiş iyi çalışır mı?
dyeryn

bu yöntemi deneyimlerimle güncelleştirilmiş yazı
dyeryn

geliştirme nihai çözüm var, ben bitince güncelleme olacak. temelde burada spesifik bölümleme ve mantıksal parçalama ile önerilen tek tablolu çözümdür.
dyeryn

Farklı bir depolama motoru yardımcı olabilir mi? InnoDb yerine InfiniDB'yi deneyebilir misiniz? Sütun verileri, erişim kalıpları büyük toplu güncelleme, menzil tabanlı okumalar ve minimum tablo bakımı gibi görünür.
dağınık

Yanıtlar:


1

aynı zamanda esneklik için anahtar / değer çifti yapısını tasarladığımız ve şu anda tablo 1.5B satırların üzerinde ve ETL'nin çok yavaş olduğu müşteri desteğinden birine bakıyorum. benim durumumda başka pek çok şey var ama bu tasarımı düşündün mü? 200 sütunun tüm mevcut değerini içeren bir satırınız olacak, bu satır Anahtar-Değer çifti tasarımında 200 satıra dönüşecektir. Verilen bir AssetID ve Date'e bağlı olarak bu tasarımla alan avantajı elde edersiniz, aslında 200 f1 ila f200 değerlerinin toplamı kaç satır vardır? % 30 od sütunlarının bile NULL değerine sahip olduğunu söylerseniz yerden tasarruf sağlar. çünkü anahtar / değer çifti tasarımında, değer id NULL ise, bu satırın tabloda olması gerekmez. ancak mevcut sütun yapısı tasarımında NULL bile yer kaplar. (% 100 emin değilim ama tablo 30'dan fazla NULL sütun varsa o zaman NULL 4bayt almak). Bu tasarımı görürseniz ve tüm 35M satırlarının 200 sütunun tümünde değerler olduğunu varsayarsanız, geçerli db tablodaki 200 * 35M = 700M satırları olur. ancak sütunları sıraya aktardığımız için tek bir tablodaki tüm sütunlarda sahip olduğunuz tablo alanında çok yüksek olmayacaktır. bu devrik işlemde aslında değerlerin NULL olduğu satırlara sahip olmayacağız. bu nedenle sorguyu bu tabloya göre çalıştırabilir ve kaç tane boş değer olduğunu görebilirsiniz ve gerçekte uygulamadan önce tablo boyutunu hedeflediğinizi tahmin edebilirsiniz. ancak sütunları sıraya aktardığımız için tek bir tablodaki tüm sütunlarda sahip olduğunuz tablo alanında çok yüksek olmayacaktır. bu devrik işlemde aslında değerlerin NULL olduğu satırlara sahip olmayacağız. bu nedenle sorguyu bu tabloya göre çalıştırabilir ve kaç tane boş değer olduğunu görebilirsiniz ve gerçekte uygulamadan önce tablo boyutunu hedeflediğinizi tahmin edebilirsiniz. ancak sütunları sıraya aktardığımız için tek bir tablodaki tüm sütunlarda sahip olduğunuz tablo alanında çok yüksek olmayacaktır. bu devrik işlemde aslında değerlerin NULL olduğu satırlara sahip olmayacağız. bu nedenle sorguyu bu tabloya göre çalıştırabilir ve kaç tane boş değer olduğunu görebilirsiniz ve gerçekte uygulamadan önce tablo boyutunu hedeflediğinizi tahmin edebilirsiniz.

ikinci avantaj okuma performansıdır. belirttiğiniz gibi, yeni sorgulama yolu bu f1 - f200 sütununun herhangi bir birleşimidir. anahtar değeri çifti ile tasarım f1 ila f200 bir sütunda bulunan "FildName" diyelim ve değerleri ikinci sütununda bulunan "FieldValue" diyelim. her iki sütunda CLUSTERED dizinine sahip olabilirsiniz. sorgunuz bu Seçimlerin BİRLİĞİ olacak.

NEREDE (DosyaAdı = 'f1' ve 5 VE 6 ARASINDA FieldValue)

BİRLİK

(DosyaAdı = 'f2' ve 8 VE 10 ARASINDA FieldValue)

vb.....

Size gerçek prod sunucusundan bazı performans numaraları vereceğim. her güvenlik TICKER için 75 fiyat sütunumuz var.


1

Çok sayıda satır eklemeniz gereken ve aynı zamanda gerçekten iyi analitik sorgu performansına ihtiyacınız olan bu tür verilerle uğraşırken (burada durumun böyle olduğunu varsayıyorum), sütunsal bir RDBMS'nin iyi bir uyum olduğunu görebilirsiniz . Infobright CE ve InfiniDB CE (her ikisi de MySQL'e takılı sütunsal depolama motorları) ve Vertica CE'ye (MySQL benzeri yerine daha fazla PostgreSQL benzeri) bir göz atın ... bu Topluluk Sürümlerinin tümü ücretsizdir (Vertica olmasa da) açık kaynak, 3 düğüm ve 1 TB veri ücretsiz ölçeklendirir). Sütunlu RDBMS'ler genellikle satır tabanlı 10-100X daha iyi "büyük sorgu" yanıt süreleri ve 5-50X daha iyi yükleme süreleri sunar. Bunları doğru bir şekilde kullanmanız gerekiyor veya kokuyorlar (tek sıralı işlemler yapmayın ... tüm işlemleri toplu bir yaklaşımla yapın), ancak doğru bir şekilde kullanıldılar. ;-)

HTH, Dave Sisk


1
3 düğümlü Vertica kurulumunda neredeyse bir milyar satırlık tıklama türü veri (stok senedi verilerinden farklı değil) var ... yaklaşık 15 saniyede tüm gün değerinde bir veri yükleyebiliriz ve 500 milisaniye menzil. Sizin durumunuzda, bu kesinlikle bir göz atmaya değer gibi görünüyor.
Dave Sisk

Ben de bunun için kefil olabilirim. Son şirketimde, aynı sayıda satır ve 8 saniyelik (ortalama) döndürülen tüm küme üzerinde basit-ish toplam sorguları olan 8 düğümlü Vertica kümemiz vardı. Daha önceki Greenplum kümemizin yaklaşık 1 / 4'ü kadar bir maliyetti.
bma
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.