Hangisi daha etkilidir: Birden çok MySQL tablosu veya bir büyük tablo?


104

MySQL veritabanımda çeşitli kullanıcı bilgilerini saklıyorum. Başlangıçta çeşitli tablolarda kurulmuştu, yani verilerin UserIds ile bağlantılı olduğu ve verileri gerektiği gibi görüntülemek ve işlemek için bazen karmaşık çağrılar yoluyla çıktı olarak verildi. Yeni bir sistem kurmak, tüm bu tabloları büyük bir ilgili içerik tablosunda birleştirmek neredeyse mantıklı.

  • Bu bir yardım mı yoksa engel mi olacak?
  • Arama, güncelleme veya arama / manipülasyonda hız faktörleri?

İşte tablo yapılarımdan bazılarının bir örneği:

  • kullanıcılar - Kullanıcı Kimliği, kullanıcı adı, e-posta, şifreli parola, kayıt tarihi, ip
  • user_details - çerez verileri, adı, adresi, iletişim bilgileri, bağlılık, demografik veriler
  • user_activity - katkılar, son çevrimiçi, son görüntüleme
  • user_settings - profil görüntüleme ayarları
  • user_interests - reklamcılık hedeflenebilir değişkenleri
  • user_levels - erişim hakları
  • user_stats - isabetler, sayımlar

Düzenleme: Şimdiye kadar tüm cevapları yükselttim, hepsinin esasen sorumu cevaplayan unsurları var.

Tabloların çoğu 1: ​​1 ilişkisine sahiptir, bu da onları normalleştirmenin ana nedenidir.

Bu hücrelerin büyük bir kısmının boş kalması muhtemelken tablo 100'den fazla sütuna yayılırsa sorunlar olacak mı?


Bu diğer soru da yardımcı olabilir
Mosty Mostacho

Yanıtlar:


66

Birden çok tablo aşağıdaki şekillerde / durumlarda yardımcı olur:

(a) farklı kişiler farklı masalar içeren uygulamalar geliştirecekse, bunları bölmek mantıklıdır.

(b) Veri toplamanın farklı bölümleri için farklı kişilere farklı türden yetkiler vermek istiyorsanız, bunları bölmek daha uygun olabilir. (Elbette, görüşleri tanımlamaya ve bunlara uygun şekilde yetki vermeye bakabilirsiniz).

(c) Verileri farklı yerlere taşımak için, özellikle geliştirme sırasında, daha küçük dosya boyutlarıyla sonuçlanan tabloların kullanılması mantıklı olabilir.

(d) Daha küçük ayak izi, tek bir varlığın belirli veri koleksiyonuna ilişkin uygulamalar geliştirirken rahatlık sağlayabilir.

(e) Bu bir olasılıktır: tek bir değer verisi olarak düşündüğünüz şey, gelecekte gerçekten birden çok değer haline gelebilir. Örneğin, kredi limiti şu an için tek bir değer alanıdır. Ancak yarın, değerleri değiştirmeye karar verebilirsiniz (başlangıç ​​tarihi, bitiş tarihi, kredi değeri). Bölünmüş tablolar artık kullanışlı olabilir.

Benim oyum, veriler uygun şekilde bölünmüş olarak birden çok tablo için olacaktır.

İyi şanslar.


3
@RohitKhatri: Bildiğim kadarıyla, birden fazla masaya sahip olmak çoğu durumda performansı artıracaktır.
Hari Harker

1
@HariHarker Cevabınız için teşekkürler, ancak bunun erişim düzeninize bağlı olduğunu anladım.
Rohit Khatri

Yakın zamana kadar tüm verileri her zaman tek bir tabloda depoluyordum, ancak düşününce, verileri performans (tabii kullanım durumuna bağlı olarak), anlambilim (bazı veriler bir farklı tablo) ve geliştirme. Örneğin, şu anda eski bir sistemin üstünde özel bir ERP sistemi geliştiriyorum. Eski veritabanı tablolarını fazladan sütunlarla genişletmem gerekiyordu. Yeni veriler için yeni tablolar yapmaya karar verdim. Bazı yeni özellikler eski sistem için kullanışlı oluyor ve artık eski sorguları çok fazla yeniden yazmak zorunda kalmadan bunları kolayca entegre edebiliyorum
Ogier Schelvis

35

Tabloları birleştirmeye denormalizasyon denir.

JOINBir bakım cehennemi yaratma pahasına daha hızlı çalıştırmak için (çok sayıda sorgu yapan) bazı sorguların yapılmasına yardımcı olabilir (veya olmayabilir) .

MySQLJOINyani sadece yöntemi kullanabilme yeteneğine sahiptir NESTED LOOPS.

Bu, sürüş tablosundaki her kayıt için MySQL, sürülen tablodaki bir döngüdeki eşleşen bir kaydı bulduğu anlamına gelir .

Bir kaydın bulunması oldukça maliyetli bir işlemdir ve saf kayıt taraması kadar uzun bir süre sürebilir.

Tüm kayıtlarınızı tek bir tabloya taşımak bu işlemden kurtulmanıza yardımcı olur, ancak tablonun kendisi büyür ve tablo taraması daha uzun sürer.

Diğer tablolarda çok sayıda kaydınız varsa, tablo taramasındaki artış, sıralı olarak taranan kayıtların faydalarını fazla ağırlaştırabilir.

Öte yandan bakım cehennemi garantilidir.


1
10000 kullanıcınız varsa ve yabancı anahtarlarla doğru şekilde ayarlanmış bir veritabanıyla birleştirme yapıyorsanız, yalnızca name = "bob" olan kullanıcılardan select * gibi bir şey yaparak yoğun aramayı yapmanız gerekir. Bob'a sahip olduğunuzda, bob'a birleştirilen tabloları bulmak için bir dizin kullanıyorsunuz, bu da bob'un kimliğini kullandığınız için önemli ölçüde daha hızlıdır. Bu, sorgunuzda bir birleştirme yapıyorsanız veya Bob'u sorgulayıp ardından bir tabloyu ayrı olarak sorguluyor olsanız da gerçekleşir. Tabii ki umarım ikinci sorgunuz Bob'un kimliğine dayanır, başka bir şeye değil.
Rudy Garcia

17

Hepsi 1: 1 ilişkiler mi? Demek istediğim, bir kullanıcı, örneğin, farklı kullanıcı seviyelerine aitse veya kullanıcıların ilgi alanları, kullanıcı ilgi alanları tablosunda birkaç kayıt olarak temsil ediliyorsa, o zaman bu tabloların birleştirilmesi hemen söz konusu olamaz.

Normalleştirme ile ilgili önceki cevaplarla ilgili olarak, veritabanı normalleştirme kurallarının performansı tamamen göz ardı ettiği ve sadece düzgün bir veritabanı tasarımının ne olduğuna baktığı söylenmelidir. Genellikle başarmak istediğiniz şey budur, ancak performans arayışında aktif olarak denormalize etmenin mantıklı olduğu zamanlar vardır.

Sonuç olarak, sorunun tablolarda kaç alan olduğuna ve bunlara ne sıklıkla erişildiğine bağlı olduğunu söyleyebilirim. Kullanıcı aktivitesi genellikle çok ilginç değilse, performans ve bakım nedenleriyle her zaman aynı kayıtta tutulması bir sıkıntı olabilir . Örneğin ayarlar gibi bazı verilere çok sık erişiliyorsa, ancak çok fazla alan içeriyorsa, tabloları birleştirmek de uygun olmayabilir. Yalnızca performans kazancıyla ilgileniyorsanız, ayarları ayrı tutmak, ancak bunları kendi oturum değişkenlerine kaydetmek gibi başka yaklaşımları da düşünebilirsiniz, böylece veritabanını onlar için çok sık sorgulamanıza gerek kalmaz.


Normalleştirmenin yalnızca düzgünlüğe odaklandığı ve performansı tamamen göz ardı ettiği şeklindeki yorumunuza tamamen katılmıyorum. Her iki senaryoda da bir değiş tokuş vardır ve normalden farklılaştırma, veri bütünlüğünü riske atar. Veritabanınızın normalleştirilmesinin, normal olmayan bir tablodan hızlı ihmal edilebilir bir performans artışı sağlamaktan ziyade, veritabanının genel performansını iyileştirdiğini söyleyebilirim.
Rudy Garcia

Tartışmanın özellikle 1: 1 ilişkiler hakkında olduğu düşünüldüğünde, tabloları bölmek normalleştirme görevi değildir , değil mi? Yinelenen bilgi yoksa, tek bir tablo olsa bile normaldir. ( 3NFNormalleştirmeyi tatmin etmeyebilir , bu yüzden bunu çözmek için ikinci bir tablodan yararlanın, ancak bu, OP'nin diğer tablolara atıfta bulunduğu şey gibi görünmüyor.)
ToolmakerSteve

14

Do bütün bu tabloları var 1-to-1ilişki? Örneğin, her kullanıcı satırında user_statsveya içinde yalnızca bir karşılık gelen satır olacak mı user_levels? Eğer öyleyse, bunları tek bir masada birleştirmek mantıklı olabilir. İlişki yine de değilse 1 to 1 , muhtemelen onları birleştirmek (normalden çıkarmak) mantıklı olmaz.

Bunları tek bir tabloya karşılık ayrı tablolarda bulundurmak, yüz binlerce veya milyonlarca kullanıcı kaydınız yoksa muhtemelen performans üzerinde çok az etkiye sahip olacaktır. Elde edeceğiniz tek gerçek kazanç, sorgularınızı birleştirerek basitleştirmektir.

ETA:

Senin Eğer endişe sahip olmakla ilgilidir çok fazla sütun , sonra düşünmek genellikle birlikte kullanmak ve bu birleştirmek Bunlar ne (gerekirse veya birkaç ayrı tablolar) ayrı bir tabloda kalanını bırakarak.

Verileri kullanma şeklinize bakarsanız, tahminimce sorgularınızın% 80'i gibi bir şeyin bu verilerin% 20'sini, kalan% 80'inin ise yalnızca ara sıra kullanıldığını göreceksiniz. Sık kullanılan% 20'yi tek bir masada birleştirin ve genellikle kullanmadığınız% 80'i ayrı tablolarda bırakın ve muhtemelen iyi bir uzlaşmaya sahip olacaksınız.


Evet, her tablonun her kullanıcı için yalnızca 1 satırı vardır, çok sayıda yinelenen veriyi yönetme zahmetinden kurtulmak için. Bu yüzden bir masa takımı düşünüyorum. Kullanıcı verileri birden çok satıra yayılmışsa, bu tabloların ana kullanıcı tablosundan ayrılmasını beklerdim.
Peter Craig

1
Her tablonun 1'e 1 ilişkisi varsa, o zaman bir tablonun kullanımı daha kolay olacaktır. Bu durumda tabloyu bölmeye gerek yoktur. Tabloyu bölmek, 1'den fazla satır olduğunu gösterir, bu da başka bir geliştiricinin onlara bu şekilde davranacağı bir duruma yol açabilir.
Richard L

Veritabanı tablo tasarımına 80/20 uygulamak çok ilginç bir düşünce. Ayrıca OOP (öncelikle bir Java geliştiricisiyim) sınıf tasarımı üzerine düşündürdü ve orada aynı şeyin etkili olup olmayacağını merak ettim (birincil% 80 uygulama işlevselliğini bir sınıfa ve geri kalanını diğer sınıflara koyun).
Zack Macomber

1
@ZackMacomber - Hayır, sınıf ayırma referansın bulunduğu yere göre yapılmalıdır . Birden çok sınıfa ayrılmanın yararı, daha küçük bir işlevsellik biriminin etrafına bir sınır çizmektir, böylece kavramanın / testin / değiştirmenin daha kolay olması ve bu birimin diğer işlevsellik birimleriyle nerede etkileşime girdiğinin netleşmesi sağlanır. Amaç, üniteler arasında az sayıda bağlantı ile çoğu bağlantıyı (referanslar, çağrılar) tek bir ünite içinde tutmaktır . Kullanım durumu başına farklı arabirimle, sınıfın uyguladığı birkaç arabirimi tanımlamak , bu bölmeye doğru yararlı bir ilk adım olabilir.
ToolmakerSteve

@ToolmakerSteve İyi düşünceler +1
Zack Macomber

9

Büyük bir tablo oluşturmak ilişkisel veritabanı ilkelerine aykırıdır. Hepsini tek bir masada birleştirmezdim. Birden fazla tekrarlanan veri örneği alacaksınız. Örneğin, kullanıcınızın üç ilgi alanı varsa, yalnızca üç farklı ilgi alanını depolamak için aynı kullanıcı verilerini içeren 3 satırınız olacaktır. Kesinlikle çoklu 'normalleştirilmiş' tablo yaklaşımını tercih edin. Veritabanı normalizasyonu için bu Wiki sayfasına bakın .

Düzenleme: Sorunuzu güncellediğiniz için cevabımı güncelledim ... İlk cevabıma şimdi daha çok katılıyorum ...

bu hücrelerin büyük bir kısmı muhtemelen boş kalacaktır

Örneğin, bir kullanıcının herhangi bir ilgi alanı yoksa, normalleştirirseniz, o kullanıcı için ilgi tablosunda basit bir satırınız olmayacaktır. Eğer her şey tek bir büyük tabloda varsa, o zaman sadece NULL içeren sütunlara (ve görünüşe göre birçoğuna) sahip olacaksınız.

Tonlarca tablonun olduğu bir telefon şirketi için çalıştım, veri almak birçok katılım gerektirebilir. Bu tablolardan okuma performansı kritik olduğunda, o zaman raporların işaret edebileceği birleştirme, hesaplama vb. Gerektirmeyen düz bir tablo (yani normalleştirilmiş bir tablo) oluşturabilecek prosedürler oluşturulur. Bunlar, daha sonra işi belirli aralıklarla çalıştırmak için bir SQL sunucu aracısı ile birlikte kullanıldığında (yani, bazı istatistiklerin haftalık görünümü haftada bir çalışır vb.).


Bu yaklaşımı seviyorum, çünkü normal olmayan veriler yalnızca geçici olarak, bir anın anlık görüntüsü olarak var oluyor. Ekleme / değiştirme / silme sorunları yok - işiniz bittiğinde atmanız yeterli.
ToolmakerSteve

7

Neden herkesin sahip olduğu temel kullanıcı bilgilerini içeren bir kullanıcı tablosuna sahip olarak ve ardından temelde kullanıcı kimliğiyle ilişkili herhangi bir anahtar, değer çifti olabilecek bir "user_meta" tablosu ekleyerek Wordpress'in yaptığı aynı yaklaşımı kullanmıyorsunuz? Dolayısıyla, kullanıcı için tüm meta bilgilerini bulmanız gerekiyorsa, bunu sorgunuza ekleyebilirsiniz. Ayrıca, oturum açma gibi şeyler için gerekmiyorsa, her zaman fazladan sorgu eklemek zorunda kalmazsınız. Bu yaklaşımın avantajı, tablonuzu kullanıcılarınıza twitter tutamaçlarını veya her bir ilgi alanını saklama gibi yeni özellikler eklemeye açık bırakır. Ayrıca, ilişkili kimliklerden oluşan bir labirentle uğraşmak zorunda kalmayacaksınız çünkü tüm meta verileri yöneten bir tablonuz var ve bunu 50 yerine yalnızca bir ilişkilendirmeyle sınırlayacaksınız.

Wordpress, özelliklerin eklentiler aracılığıyla eklenmesine izin vermek için bunu özellikle yapar, bu nedenle projenizin daha ölçeklenebilir olmasına izin verir ve yeni bir özellik eklemeniz gerekirse tam bir veritabanı revizyonu gerektirmez.


Wordpress wp_usermetatablosu geometrik olarak büyüyor. Her kullanıcı wp_usermeta, o kullanıcı için saklamak istediğimiz her meta bilgi parçası için bir satır olmak üzere tabloya X satırı ekler . Her kullanıcı için 8 özel alan tutarsanız, bu, wp_usermeta'nın users * 8satır uzunluğunda olacağı anlamına gelir . Bu performans sorunlarına neden oluyor gibi görünüyor, ancak sorunun bu olup olmadığından emin değilim ...
üçüncü kişi

1
On binlerce kullanıcınız varsa bunun performans sorunlarına nasıl neden olabileceğini görebiliyordum. Temel olarak, veri tabanının aradığınızı bulmak için kullanıcı meta tablosundaki 10000 * 8 girişi araması gerekir. Ancak Meta verilerini yalnızca gerektiğinde sorgularsanız, performansınızın daha iyi olacağını düşünürdüm. İhtiyacınız olmasa bile her zaman meta verileri soruyorsanız, sorunlarınız olabilir. Her zaman meta verilere ihtiyacınız varsa, o zaman belki de tabloları bölmek en iyi yaklaşım değildir.
Rudy Garcia

1
Daha dün, get_users()sadece sayfalandırmayı hesaplamak için tüm kullanıcıları yükleyen (kullanan ) bir WP temasıyla uğraştık . Kodu SELECT COUNT(…), sayfalandırma sorgusu kullanacak şekilde düzelttikten sonra , sayfa yükleme süresi 28 saniyeden yaklaşık 400 ms'ye çıktı. Hala performansın birleştirilmiş tablolara veya tek bir düz tabloya kıyasla nasıl olduğunu merak ediyorum… Web'de herhangi bir performans ölçütü bulmakta sorun yaşadım.
üçüncü kişi

Önceki yorumumu düşündüğümde, tabloyu bölmenin, yukarıdaki sayfalandırma örneği gibi bir nedenden ötürü, tüm kullanıcıları seçmeniz gerekmedikçe, hala verimli olduğu görülüyor. Tüm meta bilgileri alıyor olsanız da, usermeta tablosunda hala 80 bin girişiniz olacaktır. Aranacak çok şey var. Belki birisi her iki uygulamada da bir komut dosyası çalıştırarak neyin daha iyi bir yaklaşım olduğunu test edebilir ve ortalamayı elde etmek için onu 100 kez çalıştırabilir, bunu yapabilirim.
Rudy Garcia

1
Bunu bugün tekrar okudum ve 10000 * 8 girişle ilgili yorumumun doğru olduğunu fark ettim, ancak bir veritabanının çalışma şekli onu çoğunlukla sorunsuz hale getirmelidir. Herhangi bir nedenle 10000 kullanıcının tümünü ve meta bilgilerini de alıyorsanız, bu saçma olurdu. Bunu isteyeceğin herhangi bir senaryo düşünemiyorum. Bir veritabanı, yabancı anahtarlar ve indeksleme nedeniyle tek bir kullanıcı için metayı yıldırım hızıyla kolayca alacaktır. DB modelinizin doğru kurulduğunu varsayarsak.
Rudy Garcia

5

Sanırım bu "duruma göre değişir" durumlarından biri. Birden fazla masaya sahip olmak daha temiz ve muhtemelen teorik olarak daha iyidir. Ancak tek bir kullanıcı hakkında bilgi almak için 6-7 masaya katılmanız gerektiğinde, bu yaklaşımı yeniden düşünmeye başlayabilirsiniz.


1

Diğer tabloların gerçekte ne anlama geldiğine bağlı olduğunu söyleyebilirim. Bir user_details, 1'den fazla kullanıcı / kullanıcı içeriyor mu vb. İhtiyaçlarınıza en uygun normalleştirme seviyesi, taleplerinize bağlıdır.

İyi indeksi olan bir tablonuz varsa, bu muhtemelen daha hızlı olacaktır. Ancak öte yandan bakımı muhtemelen daha zordur.

Bana göre User_Details muhtemelen Kullanıcılar ile 1'e 1 ilişki olduğu için atlayabilirsiniz. Ancak geri kalanı muhtemelen kullanıcı başına çok sayıda satırdır?

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.