Bir veritabanı için ilişkisel model neden önemlidir?


61

Patronumla birlikte bir veritabanı uygulamak zorunda kalacağım bir projeye yaklaşıyorum; çok küçük bir başlangıç ​​olduğumuz için çalışma ortamı çok kişisel.

Bana daha önce şirket veritabanlarından birini vermişti ve RDBMS için okulda okuduğum (ve okudum) ile tamamen çelişiyordu. Örneğin, burada bir tablodan oluşan bütün veritabanları var (bağımsız veritabanı başına). Bu tablolardan biri 20'den fazla sütun ve bağlam için, bir tablodaki sütun adlarından bazıları :

lngStoreID | vrStoreName | lngCompanyID | vrCompanyName | lngÜrün Kimliği | vrProductName

Varlık meselesi, varlık verilerini içeren ayrı masalara sahip olması gerektiği yerde (isim, boyut, satın alınan tarih vb.), Hepsini veritabanı başına büyük bir masaya sokmasıdır.

Bu tasarımı geliştirmek istiyorum, ancak doğru şekilde normalize edilmiş ve bölümlere ayrılmış bir veri modelinin neden bu ürünü iyileştireceğini bilemiyorum. Üniversiteden veritabanı tasarımına aşina olduğum halde nasıl yapılacağını anladığım halde, bunun neden veritabanlarını geliştirdiğini bilmiyorum .

İyi bir ilişkisel şema neden veritabanını geliştirir?


33
Bir kelime: Normalleştirme.
Robert Harvey,

9
Seçmen kapat - kendini hakla! :-)
Robbie Dee

6
Yeni çalışanların teknik olarak sağlam olmasalar bile, arkasındaki nedenleri anlamadan yerleşik prosedürleri eleştirmeleri yaygındır. İlk önce patronunuzun neden bu şekilde inşa ettiğini öğrenin. Bunun iyi bir tasarım olmadığını, daha iyisini yapabilecek bilgiye (veya daha fazla zamana) sahip olmadığını çok iyi biliyor olabilir. Teklif ettiğiniz herhangi bir değişiklik, mevcut tasarımın nedenlerini saygıyla kabul ederseniz büyük olasılıkla daha olumlu bir şekilde alınacaktır.
Pedro

5
He [the boss] had given me one of his databases before and it completely went against what I was taught (and read about) in school for RDBMS<- Gerçek dünyaya hoş geldiniz!
Möoz

5
En sevdiğim ilişkisel veritabanı teklifimi hatırlattığım: "Acıyana kadar normalleştir, işe yarayana kadar denormalize et"
Jake

Yanıtlar:


70

Performans argümanı genellikle en sezgisel olanıdır. Özellikle yanlış bir şekilde normalize edilmiş bir veritabanına iyi indeksler eklemenin ne kadar zor olacağını belirtmek istersiniz (not: denormalizasyonun aslında performansı artırabileceği son durumlar vardır , ancak her ikisi de ilişkisel veritabanları ile deneyimsiz olduğunuzda, muhtemelen kolayca bu davalara bakınız).

Bir diğeri ise depolama büyüklüğü argümanıdır. Çok fazla işten çıkarmaya sahip olan denormalize bir masa çok daha fazla depolama gerektirecektir. Bu aynı zamanda performans açısından da rol oynar: Sahip olduğunuz veri miktarı arttıkça sorgularınız da yavaşlar.

Ayrıca anlaşılması biraz zor olan bir argüman var, ama aslında daha önemli çünkü ona daha fazla donanım atarak çözemezsiniz. Bu veri tutarlılığı sorunu. Düzgün bir şekilde normalize edilmiş bir veritabanı, kendi başına belirli bir ID'ye sahip bir ürünün her zaman aynı ada sahip olmasına dikkat edecektir. Ancak, denormalize edilmiş bir veritabanında bu gibi tutarsızlıklar mümkündür, bu nedenle, programın doğru olması için zaman alan ve müşteri memnuniyetinde size mal olacak hatalara neden olacak olan tutarsızlıkların önlenmesi konusunda özel dikkat gösterilmesi gerekmektedir.


19
Denormalizasyon için Önemli bir kenar durumdur veri ambarı değiştirmek asla garanti edilir verilerin büyük miktarda varsa ve depolama alanı pahasına daha hızlı ve verimli bir şekilde sorgulamak istiyorsanız, özellikle. İyi cevap, bu 3NF'den başka bir şeyin neden arzu edilebileceğinden emin olmayan herhangi bir SQL yenisi için sadece bir FYI.


11
Tutarlılık argümanının neden "anlamak zor" olduğundan emin değilim. Bana göre çok daha basit görünüyor: eğer bir değer değişirse, o zaman bu değerin tüm kopyaları güncellenmelidir. Tek bir kopyayı güncellemek, aynı verilerin yüzlerce veya binlerce kopyasını güncellemekten daha az hataya neden olur. Bu , veriler arasındaki ilişkilere eşit derecede iyi uygulanır . (İlişkiyi iki yoldan sakladıysam, ilişkinin her iki kopyasını da güncellemeliyim.) Bu, normalleştirilmiş DB'lerde oldukça yaygın bir sorundur; öyle çok (bir istisna görünüm tipi kullanımını hayata olan) uygulamada bu yolsuzluğu önlemek zor.
jpmc26

4
Bu son paragraf kalın harflerle vurgulanmalıdır. :-) Normalleştirme olmadan veri bütünlüğünü garanti etmek mümkün değildir. Girdiyi yalnızca Business Logic katmanında denetlemek bir aptaldır; normalize edilmemiş her veritabanı sonunda bir tür veri anomalisi gösterir.
DanK

2
@IsmaelMiguel Genel pratik, bunun gibi ana verilerin asla veritabanından silinmemesidir. Kullanılamıyor olduğunu belirten bir bayrak ayarlayarak sadece yumuşak bir şekilde silersiniz. Bu özel durumda, ürünler ve siparişler arasında yabancı bir anahtar ilişkisinin olması iyi bir fikirdir; bu, herhangi bir siparişin referans aldığı bir ürünü silmeye çalıştığınızda veritabanının hata yapacağı anlamına gelir.
Philipp,

24

Patronumla bir veritabanı uygulamak zorunda kalacağım ...

Özel Veritabanı Yönetimi yazılımının kullanılması oldukça kolay olabilir (üzgünüm; direnemedi).

lngStoreID | vrStoreName | lngCompanyID | vrCompanyName | lngÜrün Kimliği | vrProductName

Bu veritabanı sadece ürünün satıldığı nerede, ne zaman ve kim tarafından, o zaman "günlük" önem veriyorsa olabilir yeterince bunu karşılayacak "Tamam veritabanının" tanımı uzatmak mümkün. Bu veri başka bir şey için kullanılıyorsa , o zaman gerçekten oldukça zayıf.

Fakat ...

Bu verileri kullanan uygulama / sorgular yetersiz / yavaş yanıt veriyor mu? Değilse, o zaman çözülecek gerçek bir sorun yoktur. Tabii, görünüyor ve çirkin hissediyor, ama işe yararsa daha iyi olabileceğini öne sürmek için herhangi bir "puan" almayacaksın.

Kötü veri modellemesinden kaynaklanmış gibi görünen kesin semptomlar (yani problemler) bulabilirseniz, prototip daha iyi bir çözüm olacaktır. Bu "veritabanlarından" birinin bir kopyasını alın, verileri normalleştirin ve çözümünüzün daha iyi çalışıp çalışmadığını görün. E? Er ölçüde (ve ben tam o beklenir daha iyi herhangi bu veriler üzerinde güncelleme işlemleri olacağını kitlesel geliştirilmiş) daha sonra patronuna geri dönüp onlara gelişme göstermektedir.

Verilerin "tekli tablo görünümünü" yeniden oluşturmak ... tamamen mümkün.


11
Tekli masa weltanschauung'a karşı direnç çoğu zaman SQL ile deneyimsiz olanlardan, birleşmeyi anlamayanlardan geliyor - özellikle de dış verilerden kaynaklanan kayıplar gibi.
Robbie Dee

6
@RobbieDee Daha yaygın olarak, denormalize edilmiş verilerin tutarsızlıkla bozulduğunu gören kişilerden geliyor. Ben böyle biriyim. Sadece Phill'in önerdiği durumda bu tür bir yapıyı düşünürdüm: bu, verilerin asla güncellenmeyeceği veya yalnızca silinerek ve diğer kaynaklardan tamamen yeniden türetilerek güncellendiği bir tür kayıt / raporlama tablosu .
jpmc26

2
Uygulama böyle bir veritabanıyla kabul edilebilir bir şekilde gerçekleştirse bile, normalize edilmiş bir veritabanı gibi hala esnek değildir. Mağaza adı veya şirket adı değişirse, yalnızca bir mağaza veya şirket tablosu yerine her yerde güncellenmesi gerekir. Bazı durumlarda, aslında istediğiniz şey olabilir (örneğin, veriler çoğunlukla arşiv amaçlı toplanırsa), ancak belirli uygulama hakkında daha fazla bilgi sahibi olmamız gerekir.
Zach Lipton

1
@Zach: kabul etti, bu yüzden satış günlüğü potansiyel olarak bunun için kabul edilebilir bir durumdur. Her satış mağazası satış yapıldığı anda seçildi olursa olsun ilişkili olmak istiyorum düşünürsek, değil , o zaman "normalleştirmek" teşebbüs "mağazanın mevcut ismi" bu (bazı önemli karışıklığa yol tablo kayıt mağaza isimlerinin çünkü storeid başına sadece bir değer değil, zaman içinde bir seri olması gerekirdi)
Steve Jessop

Muhtemelen bir kural, önerilen bir normalizasyonun getirdiği tek karmaşıklık, rapor etmeleri gereken tüm sütunları toplamak için şimdi birkaç sorgunun bir araya gelmesi gerektiğidir, o zaman bu değişikliği yapmak için yürümemelisiniz: - )
Steve Jessop

14

İyi bir ilişkisel şema neden veritabanını geliştirir?

Cevap: her zaman bir veritabanını geliştirmez. Size öğretilebilecek olanın Üçüncü Normal Form olarak adlandırıldığının farkında olmalısınız .

Diğer formlar, bazı durumlarda sorunuzu yanıtlamanın anahtarı olan geçerlidir. Örneğiniz , mevcut durumu hakkında daha iyi hissetmenize yardımcı olursa, İlk Normal Form'a benziyor .

3NF kuralları bir veritabanını "geliştiren" veriler arasında ilişkiler kurar:

  1. Geçersiz verilerin sisteminize girmesini önleyin (bir ilişki 1'e 1 ise, üzerine yazılan koda rağmen bir hata yapar). Verileriniz veritabanında tutarlıysa, veritabanınızın dışında tutarsızlıklarla sonuçlanma olasılığı daha düşüktür.

  2. Kodu doğrulamanın bir yolunu sağlar (örneğin, çoktan bire bir ilişki, bir nesnenin özelliklerini / davranışlarını kısıtlayan bir sinyaldir). Veritabanını kullanmak için kod yazarken, bazen programcılar veri yapısını kodlarının nasıl çalışması gerektiğinin bir göstergesi olarak görürler. Veya veritabanı koduyla eşleşmezse yararlı geri bildirimler sağlayabilir. (Bu ne yazık ki, daha çok dilekçe düşünme gibi.)

  3. Bir veritabanı oluştururken hataları azaltmanıza önemli ölçüde yardımcı olacak kurallar sağlayın, böylece bir veritabanının ömrü boyunca herhangi bir zamanda gelebilecek rastgele gereksinimlere dayanarak oluşturmazsınız. Bunun yerine, belirli hedeflere ulaşmak için bilgileri sistematik olarak değerlendiriyorsunuz.

  4. Uygun veritabanı yapıları, verileri veri depolamayı en aza indiren, veri almak için depolama çağrılarını en aza indiren, bellek içi kaynakları en üst düzeye çıkaran ve / veya sahip olduğunuz veri kümesine ilişkin veri sıralama / manipülasyonunu en aza indiren yollarla bağlayarak performansın artmasını sağlar. ona karşı yürütme. Ancak "uygun" yapı verinin miktarına, verilerin yapısına, sorgunun türüne, sistem kaynaklarına vb. Bağlıdır. Normalleştirerek performansı daha kötü hale getirebilirsiniz (örneğin, tüm verileri 1 tablo olarak yüklerseniz - birleştirme yavaşlayabilir sorgu). İşlem işleme (OLTP) - iş zekası (veri ambarı) vs çok farklı.

Küçük veri kümelerine sahip küçük bir şirkette, şu an olduğu gibi yanlış bir şey olmadığını görebilirsiniz. Eğer büyürseniz, daha sonra "düzeltmek" acı verir, çünkü masa büyüdükçe, onu kullanan sistemler daha da yavaşlar.

Genellikle bir şirket büyüdükçe hızlı işlemleri vurgulamak istersiniz. Bununla birlikte, şimdi bu projede, şirketin daha acil ihtiyaç duyabileceği diğer şeyler yerine zaman harcarsanız, şirketiniz asla gerçekten büyümeyeceğinden bu soruna asla sahip olamayabilirsiniz. Bu "ön optimizasyon mücadelesi" - değerli zamanınızı şimdi harcadığınız yer.

İyi şanslar!


4
Belirtilmemiş ancak programcılar için önemli bir nokta, bir "şeyi" düzenlemenin, tek bir şeyi bulmak ve değiştirmek için tüm veritabanını döngülemek yerine sadece tek bir satırın düzenlenmesini gerektirmesidir.
slebetman

@slebetman Normalleştirilmiş olup olmadığına bakılmaksızın, tek bir tabloda birden çok satırı güncellemek için asla bir kod tarafı döngüsüne sahip olmamalısınız. Bir WHEREmadde kullanın . Tabii ki, bunlar hala yanlış gidebilir, ancak normalize edilmiş bir durumda daha düşük bir ihtimaldir, çünkü sadece bir sıra ile birincil anahtar ile eşleştirmeniz gerekir.
jpmc26

@ jpmc26: Veritabanını döngüye sokarak, etkilenen tüm satırları güncellemek için bir sorgu oluşturmayı kastediyorum. Bazen tek bir yer yeterlidir. Ancak, etkilenmemesi gereken satırları etkilemeden etkilenen tüm satırları almak için alt tabloları gerektiren kutsal olmayan yapılar gördüm. Tek bir sorgunun işi yapamayacağı yapılar bile gördüm (değişiklik gerektiren varlık, sıraya bağlı olarak farklı sütunlarda yer alıyor)
slebetman

Bu sorunun birçok mükemmel cevabı ve bu bir istisna değildi.
Mike Chamberlain

11

Büyük bir "tanrı masası" kullanmanın kötü olmasının birçok nedeni var. Bir telafi örneği veri tabanı ile ilgili sorunları açıklamaya çalışacağım. Spor etkinliklerini modellemeye çalıştığınızı varsayalım. Oyunları ve bu oyunlarda oynayan takımları modellemek istediğinizi söyleyeceğiz. Birden fazla tabloya sahip bir tasarım şöyle görünebilir (bilerek bu çok basittir, bu nedenle daha fazla normalleşmenin uygulanabileceği yerlere takılmayın):

Teams
Id | Name | HomeCity

Games
Id | StartsAt | HomeTeamId | AwayTeamId | Location

ve tek bir masa veritabanı böyle görünecek

TeamsAndGames
Id | TeamName | TeamHomeCity | GameStartsAt | GameHomeTeamId | GameAwayTeamId | Location

İlk önce, bu masalarda endeks oluşturmaya bakalım. Bir takım için şehirdeki bir indekse ihtiyacım olursa, onu Teamsmasaya ya da TeamsAndGamesmasaya kolayca ekleyebilirim . Ne zaman bir indeks oluşturursanız, bir yerde diskte saklanması ve tabloya satırlar eklenerek güncellenmesi gerektiğini unutmayın. TeamsMasanın durumunda bu oldukça basittir. Yeni bir takım ekledim, veritabanı endeksi günceller. Peki ya ne için TeamsAndGames? Peki, aynısıTeamsörnek. Bir takım eklerim, indeks güncellenir. Ama bir oyun eklediğimde de oluyor! Bu alan bir oyun için boş olsa da, endeks hala o oyun için güncellenmeli ve diskte saklanmalıdır. Bir indeks için bu kulağa fena gelmiyor. Ancak bu tabloya sıkışmış birçok varlık için birçok endekse ihtiyacınız olduğunda, endeksleri depolayan çok fazla alan harcarsınız ve uygulama yapmadıkları şeyler için onları güncelleyen çok fazla işlemci zamanı harcarsınız.

İkincisi, veri tutarlılığı. İki ayrı masa kullanılması durumunda, hangi takımların bir oyunda oynadığını tanımlamak Gamesiçin Teamsmasadan masaya yabancı anahtarlar kullanabilirim . Ve varsayarak yapamıyor HomeTeamIdve AwayTeamIdsütunlar null değil, veritabanı Yatırdığım her oyun 2 takım var olmasını sağlayacaktır ve bu ekipler veritabanında mevcut olduğunu. Peki ya tek masa senaryosu? Eh, bu tabloda birden fazla varlık olduğu için, bu sütunlar null edilebilir olmalıdır (onları null yapamaz hale getirebilir ve orada çöp verilerini zorlayabilir, ama bu sadece korkunç bir fikirdir). Bu sütunlar null ise, veritabanı artık iki takımı olan bir oyun eklediğinizde artık garanti edemez.

Ama yine de bunun için gitmeye karar verirseniz ne olacak? Yabancı anahtarları, bu alanların aynı tabloda başka bir varlığa işaret edeceği şekilde ayarlarsınız. Ancak şimdi veritabanı, bu varlıkların doğru tür olduklarından değil, tabloda bulunduğundan emin olacaktır. Kolayca GameHomeTeamIdbaşka bir oyunun kimliğini ayarlayabilir ve veritabanı hiç bir şekilde şikayet etmez. Birden fazla tablo senaryosunda bunu denediyseniz, veritabanı uygun bir sonuç verir.

Bu meseleleri hafifletmeyi deneyebilirsiniz, "peki, bunu asla asla kodda yapmadığımızdan emin olacağız" diyerek. İlk defa hatasız kod yazma yeteneğinize ve bir kullanıcının deneyebileceği her tuhaf kombinasyonunu hesaba katma yeteneğinize güveniyorsanız, hemen devam edin. Şahsen ben de bu şeylerden birini yapma yeteneğimden emin değilim, bu yüzden veritabanının bana ekstra güvenlik ağı vermesine izin vereceğim.

(Tasarımınız, yabancı anahtarlar kullanmak yerine satırlar arasında tüm ilgili verileri kopyaladığınız bir yerdeyse, bu daha da kötüleşir. Yazım / diğer veri tutarsızlıklarının çözülmesi zor olacaktır. "ya da kasıtlıysa (çünkü onlar iki ayrı insan)?)

Üçüncüsü, hemen hemen her sütunun boş olması veya kopyalanmış veya çöp verilerle doldurulması gerekir. Bir oyunun bir TeamNameveya ihtiyacı yok TeamHomeCity. Bu yüzden her oyunun içinde bir tür yer tutucusuna ya da null olması gerekiyor. Ve null ise, veritabanı mutlu bir şekilde hayırlı bir oyun alacaktır TeamName. İş mantığınız asla gerçekleşmemesi gerektiğini söylese bile, adı olmayan bir takımı da alacak.

Ayrı tablolar (geliştirici aklını korumak da dahil olmak üzere) isteme nedeniniz için bir kaç neden vardır. Daha büyük bir masanın daha iyi olmasının birkaç nedeni bile vardır (denormalizasyon bazen performansı arttırır). Bu senaryolar az ve çok arasındadır (ve genellikle bunun gerçekten bir sorun olduğunu, eksik bir endeks veya başka bir şey olmadığını göstermek için performans ölçütleriniz olduğunda ele alınmalıdır).

Son olarak, bakımı kolay bir şey geliştirin. Sırf "işe yarıyor" tamam demek değil. Tanrı tablolarını korumaya çalışmak (tanrı sınıfları gibi) bir kabustur. Daha sonra acı çekmek için kendini hazırlıyorsun.


1
"Takımlar: Id | Name | HomeCity". Veri şemanızın uygulamanızı yanlış yapmadığından emin olun, Super Bowl XXXIV’in LA Rams tarafından kazanıldığını iddia edin. Oysa SB XXXIV , şu anda LA Rams olarak bilinen takım tarafından kazanılan tüm şampiyonluklar için bir sorguda görünmelidir. Daha iyi ve daha kötüsü “tanrı tabloları” var ve kesinlikle kötü bir tablo sundunuz. Daha iyisi "oyun kimliği | ev sahibi takım adı | ev sahibi şehir şehri | deplasman takımı adı | deplasman ekibi şehri | oyun | | "New Orleans Saints @ Chicago Bears 1p Eastern" gibi bilgileri modellemeye yönelik ilk girişim olarak ortaya çıkıyor.
Steve Jessop

6

Günün Alıntı: " Teori ve pratik aynı olmalı ... teoride "

Denormalize masa

Benzersiz bekletme tablosunda yedekli verilerin bulunması bir avantaja sahiptir: satırlarında raporlamayı kodlaması çok kolay ve yürütmesi çok hızlı yapar, çünkü herhangi bir birleştirme yapmanız gerekmez. Ancak bu yüksek maliyetle:

  • Yedekli ilişkilerin kopyalarını tutar (örneğin IngCompanyIDve vrCompanyName). Ana verilerin güncellenmesi normalleştirilmiş bir şemada olduğundan çok daha fazla satırın güncellenmesini gerektirebilir.
  • Her şeyi karıştırır. Veri tabanı düzeyinde kolay erişim kontrolü sağlayamazsınız, örneğin, A kullanıcısının yalnızca şirket bilgilerini ve yalnızca B ürün bilgisini güncelleyebilmesini sağlama.
  • Tutarlılık kurallarını veritabanı düzeyinde sağlayamazsınız (örneğin, bir şirket kimliği için yalnızca bir şirket adı olmasını zorunlu kılan birincil anahtar).
  • Normalize edilmiş tabloların boyutundan ve çeşitli endekslerin istatistiklerinden faydalanarak karmaşık bir sorgu için en uygun erişim stratejilerini tanımlayabilen DB iyileştiricisinden tam olarak yararlanamazsınız. Bu, birleşmeden kaçınmanın sınırlı yararını hızla telafi edebilir.

Normalize masa

Yukarıdaki dezavantajlar normalleştirilmiş şema için avantajlardır. Tabii ki, sorgular yazmak için biraz daha karmaşık olabilir.

Kısacası, normalleştirilmiş şema , verileriniz arasındaki yapı ve ilişkileri çok daha iyi ifade eder. Kışkırtıcı olacağım ve bir dizi sipariş edilen ofis çekmecesini kullanmak için gereken disiplin ile çöp kutusunun kullanım kolaylığı arasındaki farkla aynı olduğunu söyleyeceğim.


5

Bence sorunuzun en az iki kısmı var:

1. Neden farklı türdeki varlıklar aynı tabloda depolanmamalıdır?

Buradaki en önemli cevaplar kod okunabilirliği ve hızıdır. A SELECT name FROM companies WHERE id = ?, a'dan çok daha okunaklıdır SELECT companyName FROM masterTable WHERE companyId = ?ve kazayla saçma sapan sorgulama olasılığınız daha düşüktür (örneğin SELECT companyName FROM masterTable WHERE employeeId = ?, şirketler ve çalışanlar farklı tablolarda depolandığında mümkün olmaz). Hız gelince, bir veritabanı tablosundan gelen veriler ya tam tablonun sırayla okunmasıyla ya da bir endeksin okunmasıyla elde edilir. Tablo / dizin daha az veri içeriyorsa her ikisi de daha hızlıdır ve veriler farklı tablolarda depolanıyorsa bu geçerlidir (ve tablolardan / dizinlerden yalnızca birini okumanız gerekir).

2. Niçin tek tipte varlıklar farklı tablolarda depolanan alt varlıklara bölünmelidir?

Buradaki sebep çoğunlukla veri tutarsızlıklarını önlemektir. Tekli masa yaklaşımıyla, sipariş yönetimi sistemi için müşterinin adını, müşterinin adresini ve müşterinin sipariş ettiği ürünü tek bir varlık olarak saklayabilirsiniz. Bir müşteri birden fazla ürün sipariş ettiğinde, veritabanınızdaki müşterinin adı ve adresi için birden fazla örneğiniz olur. En iyi durumda, veritabanınızda yinelenen veriler var, bu da onu biraz yavaşlatabilir. Ancak daha da kötüsü, birisinin (veya bazı kodların) veri girildiğinde hata yapmış olması, böylelikle şirketlerin veritabanında farklı adreslerle sonuçlanmasıdır. Bu tek başına yeterince kötü. Fakat bir şirketin adresini ismine göre sorgulamak isteseydiniz (örneğin;SELECT companyAddress FROM orders WHERE companyName = ? LIMIT 1) sadece keyfi olarak iade edilen iki adresden birini alırsınız ve bir tutarsızlık olduğunu bile fark etmezsiniz. Ancak sorguyu her çalıştırdığınızda, sorgunuzun DBMS tarafından dahili olarak nasıl çözümlendiğine bağlı olarak, aslında farklı bir adres alabilirsiniz. Bu muhtemelen uygulamanızı başka bir yerde yıkacaktır ve bu kırılmanın kök nedenini bulmak çok zor olacaktır.

Çok masalı yaklaşımla, şirket adından şirket adresine işlevsel bir bağımlılık olduğunu fark edersiniz (bir şirketin yalnızca bir adresi varsa), (şirket adı, şirket adresi) dizisini tek bir tabloda (örn. company) ve (productId, companyName) başka bir tabloda (örn. order) sıralanır . Tablodaki bir UNIQUEkısıtlama companydaha sonra her bir şirketin veritabanında yalnızca tek bir adres bulunduğunu ve böylece şirket adresleri için hiçbir tutarsızlığın ortaya çıkmayacağını zorlayabilir.

Not: Uygulamada, performans nedenleriyle, muhtemelen her bir şirket için benzersiz bir şirket oluşturur ve şirket adını doğrudan kullanmak yerine, yabancı bir anahtar olarak kullanırsınız. Ancak genel yaklaşım aynı kalır.


3

TL; DR - Onlar nasıl dayanan veritabanı tasarlarken onlar onlar okuldayken öğretildi.

Bu soruyu 10 yıl önce yazabilirdim. Seleflerimin neden veritabanlarını yaptıkları gibi tasarladıklarını anlamam biraz zaman aldı. Ya biriyle çalışıyorsun:

  1. Excel'i bir veritabanı olarak kullanarak veritabanı tasarım becerilerinin çoğunu veya
  2. Okuldan çıktığında en iyi uygulamaları kullanıyorlar.

Masanızda kimlik numaralarınız olduğundan 1 numara olduğundan şüphelenmiyorum, bu yüzden 2 numara alacağım.

Okuldan çıktıktan sonra AS / 400 (yani IBM i) kullanan bir dükkanda çalışıyordum . Veritabanlarını tasarlama şekillerinde bazı garip şeyler buldum ve veritabanlarını nasıl tasarlayacağımı nasıl öğrendiğimi takip etmek için değişiklikler yapmaya başladığımızı savunmaya başladım. (O zamanlar aptalım)

Hastaların neden bu şekilde yapıldığını açıklamak için daha yaşlı bir programcı aldı. Şemayı değiştirmemişlerdi çünkü benden daha eski olan programların kırılmasına neden olacaktı. Kelimenin tam anlamıyla, bir programın kaynak kodunun doğmadan önceki yılın yaratılış tarihi vardı. Üzerinde çalıştığımız sistemdeki programları , veritabanınızın sorgu planlayıcısının sizin için kullandığı tüm mantığı ve işlemleri uygulamak zorunda kaldı. (Sorgularınızdan birinde EXPLAIN çalıştırarak bunu görebilirsiniz)

Uygulamaya çalıştığım teknikler konusunda güncelti, ancak sistemi çalışır durumda tutmak, "öğretildiğim şeye karşı çıktığı için" değişiklik yapmaktan daha önemliydi. İkimizden başladığımız her yeni proje, yapabildiğimiz ilişkisel modelden en iyi şekilde faydalandı. Ne yazık ki, o zamanın diğer programcıları / danışmanları hala veritabanlarını bu sistemin eski kısıtlamaları ile çalışıyormuş gibi tasarladılar.


Karşılaştığım şeye dair ilişkisel modele uymayan bazı örnekler:

  • Tarihler , gerçek tarihi almak için bir tarih tablosuna katılmayı gerektiren Jülyen gün sayıları olarak kaydedildi .
  • Aynı tipteki sıralı sütunlarla denormalize tablolar (örneğin code1,code2, ..., code20)
  • NxM uzunluk CHAR, M uzunlukları N dizelerinin bir dizisini temsil eder.

Bu tasarım kararları için bana verilen nedenlerin tümü, veritabanı ilk tasarlandığında sistemin kısıtlamalarına dayanıyordu.

Tarihler - Bir tarihi işlemek için tarih işlevlerini (hangi ay veya gün veya hafta içi gün) kullanmamın, bu bilgilerle birlikte her olası tarihin bir tablosunu oluşturmaktan daha fazla işlem süresi aldığı söylendi.

Aynı tipteki sıralı sütunlar - İçlerinde bulundukları programlama ortamı, bir programın satırın parçası üzerinde bir dizi değişkeni yaratmasına izin verir. Ve okuma işlemlerinin sayısını azaltmanın daha kolay bir yoluydu.

NxM Uzunluk CHAR sütunları - Dosya okuma işlemlerini azaltmak için yapılandırma değerlerini bir sütuna sokmak daha kolaydı.

Sahip oldukları programlama ortamını yansıtacak şekilde eşdeğer bir kötü düşünülmüş örnek:

#define COURSE_LENGTH 4
#define NUM_COURSES 4
#define PERIOD_LENGTH 2

struct mytable {
    int id;
    char periodNames[NUM_COURSES * PERIOD_LENGTH];  // NxM CHAR Column
    char course1[COURSE_LENGTH];
    char course2[COURSE_LENGTH];
    char course3[COURSE_LENGTH];
    char course4[COURSE_LENGTH];
};

...

// Example row
struct mytable row = {.id= 1, .periodNames="HRP1P2P8", .course1="MATH", .course2="ENGL", .course3 = "SCI ", .course4 = "READ"};

char *courses; // Pointer used to access the sequential columns
courses = (char *)&row.course1;


for(int i = 0; i < NUM_COURSES; i++) {

    printf("%d: %.*s -> %.*s\n",i+1, PERIOD_LENGTH, &row.periodNames[PERIOD_LENGTH * i], COURSE_LENGTH,&courses[COURSE_LENGTH*i]);
}

çıktılar

1: İK -> MAT
2: P1 -> İNGİLİZCE
3: P2 -> SCI
4: P8 -> OKUYUN

Bana söylendiğine göre, bunun bir kısmının en iyi uygulama olduğu düşünülüyordu.

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.