Kullanıcı Tanımlı Alanlar için bir veritabanı nasıl tasarlanır?


145

Gereksinimlerim:

  • Herhangi bir veri türünün Kullanıcı Tanımlı alanlarını dinamik olarak ekleyebilmemiz gerekir
  • UDF'leri hızlı bir şekilde sorgulayabilmemiz gerekiyor
  • Veri tipine göre UDF'lerde hesaplamalar yapabilmek gerekir
  • UDF'leri veri tipine göre sıralayabilmeli

Diğer bilgiler:

  • Öncelikle performansı arıyorum
  • UDF verisi eklenebilen birkaç milyon Ana kayıt var
  • En son kontrol ettiğimde, mevcut veritabanımızda 50milden fazla UDF kaydı vardı
  • Çoğu zaman, bir UDF sadece birkaç bin Master kaydına eklenir, hepsi değil
  • UDF'ler birleştirilmez veya anahtar olarak kullanılmaz. Bunlar yalnızca sorgular veya raporlar için kullanılan verilerdir

Seçenekler:

  1. StringValue1, StringValue2 ... IntValue1, IntValue2, ... vb. İle büyük bir tablo oluşturun.

  2. Gerektiğinde isteğe bağlı yeni bir sütun ekleyen dinamik bir tablo oluşturun. Ayrıca bu fikri sevmiyorum çünkü her sütunu dizine eklemediğiniz sürece performansın yavaş olacağını hissediyorum.

  3. UDFName, UDFDataType ve Value içeren tek bir tablo oluşturun. Yeni bir UDF eklendiğinde, yalnızca bu verileri çeken ve belirtilen türde ayrıştıran bir Görünüm oluşturun. Ayrıştırma ölçütlerini karşılamayan öğeler NULL döndürür.

  4. Her veri türü için bir tane olmak üzere birden çok UDF tablosu oluşturun. Yani UDFStrings, UDFDates, vb. İçin tablolarımız olurdu. Muhtemelen # 2 ile aynı şeyi yapar ve yeni bir alan eklendiğinde otomatik olarak bir Görünüm oluşturur

  5. XML Veri Türleri? Bunlarla daha önce çalışmadım ama bahsettiklerini gördüm. Bana istediğim sonuçları, özellikle performansla verip vermeyeceklerinden emin değilim.

  6. Başka bir şey?


7
Martin Fowler, 2 (kullanıcı tarafından güncellenebilir şema) veya 5 (dizine eklenmiş XML LOB) önermektedir
Neil McGuigan

Ayrıca dinamik veritabanı şemalarıyla ilgili StackOverflow sorusuna da bakın .
FloverOwe

Yanıtlar:


49

Performans birincil endişe ise, # 6 ... UDF başına bir tablo ile gitmek istiyorum (gerçekten, bu # 2 bir varyantıdır). Bu yanıt özellikle bu duruma ve açıklanan veri dağıtım ve erişim modellerinin açıklamasına göre uyarlanmıştır.

Artıları:

  1. Bazı UDF'lerin genel veri kümesinin küçük bir kısmı için değerlere sahip olduğunu belirttiğiniz için, ayrı bir tablo size en iyi performansı verir çünkü bu tablo yalnızca UDF'yi desteklemek için gereken kadar büyük olacaktır. Aynı durum ilgili endeksler için de geçerlidir.

  2. Toplama veya diğer dönüşümler için işlenmesi gereken veri miktarını sınırlandırarak da hız artışı elde edersiniz. Verileri birden çok tabloya bölmek, UDF verileri üzerinde toplama ve diğer istatistiksel analizlerden bazılarını gerçekleştirmenizi, ardından toplanmayan öznitelikleri almak için bu sonucu yabancı anahtar yoluyla ana tabloya birleştirmenizi sağlar.

  3. Verilerin gerçekte ne olduğunu yansıtan tablo / sütun adlarını kullanabilirsiniz.

  4. Veri alanlarını tanımlamak için veri türlerini, kontrol kısıtlamalarını, varsayılan değerleri vb. Kullanmak için tam kontrole sahipsiniz. Anında veri türü dönüştürmesinden kaynaklanan performans vuruşunu hafife almayın. Bu tür kısıtlamalar ayrıca RDBMS sorgu iyileştiricilerinin daha etkili planlar geliştirmesine yardımcı olur.

  5. Yabancı anahtar kullanmanız gerektiğinde, yerleşik bildirim referans bütünlüğü tetikleyici tabanlı veya uygulama düzeyinde kısıtlama zorlamasıyla nadiren gerçekleştirilir.

Eksileri:

  1. Bu çok fazla tablo oluşturabilir. Şema ayrımının ve / veya bir adlandırma kuralının uygulanması bunu hafifletir.

  2. UDF tanımını ve yönetimini çalıştırmak için daha fazla uygulama koduna ihtiyaç vardır. Bu hala orijinal seçenekleri 1, 3, ve 4 daha az gerekli kod bekliyoruz.

Diğer Hususlar:

  1. UDF'lerin gruplandırılması için anlamlı olacak verilerin doğası hakkında bir şey varsa, bu teşvik edilmelidir. Bu şekilde, bu veri elemanları tek bir tabloda birleştirilebilir. Örneğin, renk, boyut ve maliyet için UDF'leriniz olduğunu varsayalım. Verilerdeki eğilim, bu verilerin çoğu örneğinin

     'red', 'large', 45.03 

    ziyade

     NULL, 'medium', NULL

    Böyle bir durumda, 1 tablodaki 3 sütunu birleştirerek fark edilir bir hız cezasına maruz kalmazsınız çünkü birkaç değer NULL olur ve 2 sütunun daha fazlasına ihtiyaç duymazsınız, bu da 3 sütunun tümüne erişmeniz gerektiğinde 2 daha az birleşim gerektirir .

  2. Çok nüfuslu ve sık kullanılan bir UDF'den bir performans duvarına çarparsanız, bu ana tabloya dahil edilmek üzere düşünülmelidir.

  3. Mantıksal tablo tasarımı sizi belirli bir noktaya götürebilir, ancak kayıt sayıları gerçekten çok büyük olduğunda, RDBMS'niz tarafından hangi tablo bölümleme seçeneklerinin sağlandığına da bakmaya başlamalısınız.


1
Denetim Listeleri! Ben ve Phil arasındaki şaka, umarım bu kurallara aykırı değildir.
GunnerL3510

Teşekkürler, sanırım bunun bazı varyasyonlarını yapacağım. UDF verilerimizin çoğu, yalnızca referans amaçlı olarak kalması gereken eşlenmemiş içe aktarma alanlarından gelir, bu yüzden bunları tek bir tabloya koymak istiyorum. Diğer UDF'ler gerektiği gibi tanımlanır (bunları önceden tanımlayamıyorum .. genellikle bir işlemi değiştirdiğimizde veya birkaç ay boyunca özel bir şeyi izlemeye karar verdiğimizde oluşturulur) ve sorgularda yaygın olarak kullanılır. Sanırım bu değerlerin her mantıksal birimi için ayrı bir tablo yapacağım.
Rachel

Ben tarihli / sürüm UDF olan bir tablo ile çalışıyorum , en son değerleri almak için stackoverflow.com/a/123481/328968 , bu yöntemi kullanın .
Peter

22

Ben var yazılı bu sorunla ilgili bir sürü . En yaygın çözüm, 3. seçenekte açıkladığınız şeye benzeyen Entity-Attribute-Value antipattern'dir. Veba gibi bu tasarımdan kaçının .

Gerçekten dinamik özel alanlara ihtiyaç duyduğumda bu çözüm için kullandığım, bunları bir XML blobunda saklamaktır, böylece herhangi bir zamanda yeni alanlar ekleyebilirim. Ancak hızlı hale getirmek için, aramanız veya sıralamanız gereken her alan için ek tablolar oluşturun (alan başına bir tablo değil - yalnızca aranabilir bir tablo) alan ). Buna bazen ters dizin tasarımı denir.

2009'dan bu çözümle ilgili ilginç bir makaleyi buradan okuyabilirsiniz: http://backchannel.org/blog/friendfeed-schemaless-mysql

Veya belge başına özel alanlara sahip olmanız beklenen belge tabanlı bir veritabanı kullanabilirsiniz. Solr'ı seçerdim .


1
# 3 seçeneğinden neden kaçınmam gerektiğini açıklayabilir misiniz? Bazı örneklerinize baktım, ama gerçekten yapmaya çalıştığımla aynı değiller. Ben sadece ekstra veri depolamak için bir yer istiyorum, tüm özellikleri depolamak için bir yer değil.
Rachel

2
Yeni başlayanlar için, NULL DEĞİL bir özelliği kim yaparsınız? Tüm nitelikleri BENZERSİZ yapmadan bir özniteliği nasıl UNIQUE yaparsınız? Oradan devam ediyor. RDBMS'nin zaten size sağladığı özellikleri sağlamak için uygulama kodunu yazmanız gerekir, hatta basitçe bir mantıksal varlık kaydı eklemek ve geri almak için bir tür haritalama sınıfı yazmak zorunda kalabilirsiniz.
Bill Karwin

2
Kısa cevap "veri ve meta verileri karıştırmayın" şeklindedir. Varda sütunları oluşturmak fieldnameveya tablenamemeta veri tanımlayıcılarını veri dizeleri olarak saklamakta ve bu birçok sorunun başlangıcıdır. Ayrıca bkz. En.wikipedia.org/wiki/Inner-platform_effect
Bill Karwin

2
@Thomas: Tersine çevrilmiş dizin tasarımında, veri türleri ve UNIQUE ve FOREIGN KEY gibi kısıtlamalar için standart şema çözümlerini kullanabilirsiniz. EAV kullandığınızda bunlar işe yaramaz. EAV ile tersine çevrilmiş endeks paylaşımlarını, yalnızca sıra başına farklı nitelikleri desteklediği için ilişkisel olmama özelliğinin kabul ediyorum, ancak bu bir uzlaşma noktası.
Bill Karwin

2
@thitami, Yıllar boyunca öğrendiğim şey, herhangi bir çözümün uygulamanız için doğru çözüm olabileceğidir. EAV bile belirli bir uygulama için en az kötü çözüm olabilir. Sorgularınızı bilmeden bir optimizasyon stratejisi seçemezsiniz. Her türlü optimizasyon, diğer sorguların pahasına belirli sorguları geliştirir.
Bill Karwin

10

Muhtemelen aşağıdaki yapıya ait bir tablo oluşturacağım:

  • varchar Adı
  • varchar Türü
  • ondalık SayıDeğer
  • varchar StringValue
  • date DateValue

Kesin tipler elbette ihtiyaçlarınıza (ve tabii ki kullandığınız dbms'ye) bağlıdır. Ayrıca int ve booleans için NumberValue (ondalık) alanını da kullanabilirsiniz. Başka türlere de ihtiyacınız olabilir.

Değere sahip olan Ana kayıtlara bir bağlantıya ihtiyacınız var. Her bir ana tablo için bir kullanıcı alanları tablosu oluşturmak ve basit bir yabancı anahtar eklemek muhtemelen en kolay ve en hızlıdır. Bu şekilde ana kayıtları kullanıcı alanlarına göre kolay ve hızlı bir şekilde filtreleyebilirsiniz.

Bir çeşit meta veri bilgisine sahip olmak isteyebilirsiniz. Böylece aşağıdakilerle sonuçlanırsınız:

Tablo UdfMetaData

  • int id
  • varchar Adı
  • varchar Türü

Tablo MasterUdfDeğerleri

  • int Master_FK
  • int MetaData_FK
  • ondalık SayıDeğer
  • varchar StringValue
  • date DateValue

Ne yaparsan yap, ben ederim değil dinamik tablo yapısını değiştirmek. Bir bakım kabusu. Ben de olur değil onlar çok çok yavaş, XML yapılarını kullanırlar.


Stratejinizi beğendim ve belki de tercih ettim ama 2017'de farklı bir şey seçer misiniz? like json
maztt

Projemizde, json'a benzer bir şeye serileşen kendi veri yapılarımızı uyguladık. Döküm olmadan ve mükemmel programlama dili entegrasyonu ile veri okumak ve yazmak için bir tipesave arayüze sahiptir. Bu gerçekten muhteşem. Veritabanlarındaki tüm bu tür "belgeler" ile aynı soruna sahiptir. Spesifik değerleri sorgulamak zordur ve "belge" dışındaki verilere kolayca başvuramaz. Kullanıma bağlı olarak, her ikisi de bir sorun değildir.
Stefan Steinegger

Bunun yanı sıra, 2011 yılında önerdiğim IMHO hala geçerli bir çözüm.
Stefan Steinegger

10

Bu MongoDB veya CouchDB gibi ilişkisel olmayan bir çözümle daha iyi çözülebilecek bir sorun gibi görünüyor.

Her ikisi de dinamik şema genişlemesine izin verirken aradığınız grup bütünlüğünü korumanıza izin verir.

Bill Karwin'e katılıyorum, EAV modeli sizin için performans dolu bir yaklaşım değil. İlişkisel bir sistemde ad-değer çiftlerini kullanmak özünde kötü değildir, ancak yalnızca ad-değer çifti tam bir bilgi kümesi oluşturduğunda iyi çalışır. Bunu kullanırken, çalışma zamanında bir tabloyu dinamik olarak yeniden yapılandırmaya zorlarsanız, her türlü şey zorlaşmaya başlar. Sorgulama, pivot bakımında bir alıştırma haline gelir veya tuple rekonstrüksiyonunu nesne katmanına itmeye zorlar.

Nesne katmanınıza şema kurallarını gömmeden null veya eksik bir değerin geçerli bir giriş mi yoksa giriş eksikliği mi olduğunu belirleyemezsiniz.

Şemanızı verimli bir şekilde yönetme yeteneğini kaybedersiniz. 100 karakterlik bir varchar "değer" alanı için doğru tip mi? 200 karakter? Bunun yerine nvarchar mı olmalı? Zor bir takas olabilir ve setinizin dinamik doğasına yapay sınırlar koymak zorunda kalabilirsiniz. "X tanımlı x alanınız olabilir ve her biri yalnızca y karakter uzunluğunda olabilir.

MongoDB veya CouchDB gibi belge odaklı bir çözümle, bir kullanıcıyla ilişkili tüm nitelikleri tek bir grupta tutarsınız. Birleşimler bir sorun olmadığından, hayat mutludur, çünkü bu ikisinin hiçbiri yutturmacaya rağmen birleşimlerle iyi sonuç vermez. Kullanıcılarınız, yaklaşık 4 MB'a ulaşana kadar yönetilmesi zor olmayan uzunluklarda istedikleri sayıda (veya izin vereceğiniz) özellik tanımlayabilir.

ACID düzeyinde bütünlük gerektiren verileriniz varsa, çözümü ilişkisel veritabanınızda yaşayan yüksek bütünlüklü veriler ve ilişkisel olmayan bir mağazada yaşayan dinamik verilerle çözümü bölmeyi düşünebilirsiniz.


6

Özel sütunlar ekleyen bir kullanıcı sağlasanız bile, bu sütunlardaki sorgulamanın iyi performans göstermesi gerekmez. Sorgu tasarımına, iyi performans göstermelerine izin veren birçok yön vardır, bunların en önemlisi, ilk etapta nelerin depolanması gerektiğine dair uygun özelliklerdir. Dolayısıyla, temel olarak, kullanıcıların spesifikasyonlar hakkında düşünülmeden şema oluşturmasına izin vermek ve bu şemadan hızlı bir şekilde bilgi elde edebilmek mi istiyorsunuz? Eğer öyleyse, özellikle kullanıcının veriler üzerinde sayısal analiz yapmasına izin vermek istiyorsanız, böyle bir çözümün iyi ölçeklenmesi olası değildir.

seçenek 1

IMO bu yaklaşım, şemanın ne anlama geldiği konusunda hiçbir bilgi sahibi olmayan şema verir; bu da felaket için bir reçete ve rapor tasarımcıları için bir kabus. Yani, hangi sütunun hangi verileri depoladığını bilmek için meta verilere sahip olmanız gerekir. Bu meta veriler bozulursa, verilerinizi hortumlama potansiyeli vardır. Ayrıca, yanlış verileri yanlış sütuna koymayı kolaylaştırır. ("Ne? String1, manastırların adını içeriyor mu? Chalie Sheen'in en sevdiği ilaçlar olduğunu düşündüm.")

Seçenek 3,4,5

IMO, gereksinimler 2, 3 ve 4 bir EAV varyasyonunu ortadan kaldırır. Bu verileri sorgulamanız, sıralamanız veya hesaplamalar yapmanız gerekiyorsa, bir EAV Cthulhu'nun rüyası ve geliştirme ekibinizin ve DBA'nın kabusu. EAV'lar performans açısından bir darboğaz oluşturacak ve istediğiniz bilgiye hızla ulaşmak için ihtiyacınız olan veri bütünlüğünü vermeyecektir. Sorgular hızla Gordian düğümlerini çaprazlayacak.

Seçenek 2,6

Bu gerçekten bir seçenek bırakıyor: spesifikasyonları toplayın ve sonra şemayı oluşturun.

İstemci depolamak istediği veriler üzerinde en iyi performansı almak istiyorsa, ihtiyaçlarını anlamak için bir geliştiriciyle birlikte çalışma sürecinden geçerek, olabildiğince verimli bir şekilde saklanması gerekir. Tablo şemasına göre dinamik olarak bir form oluşturan kod içeren tabloların geri kalanından ayrı bir tabloda saklanabilir. Sütunlarda genişletilmiş özelliklere izin veren bir veritabanınız varsa, bunları form oluşturucunun güzel etiketler, araç ipuçları vb. Kullanmasına yardımcı olmak için kullanabilirsiniz, böylece gerekli olan tek şey şemayı eklemektir. Her iki durumda da, raporları verimli bir şekilde oluşturmak ve çalıştırmak için verilerin düzgün bir şekilde saklanması gerekir. Söz konusu verilerde çok sayıda boş değer varsa, bazı veritabanları bu tür bilgileri saklama yeteneğine sahiptir. Örneğin,

Bu sadece analiz, filtreleme veya sıralama yapılmayacak bir veri çantası olsaydı, bir EAV'ın bazı varyasyonlarının hile yapabileceğini söyleyebilirim. Ancak, gereksinimleriniz göz önüne alındığında, bu yeni sütunları ayrı tablolarda saklasanız ve bu tablolardan dinamik olarak formlar oluştursanız bile, en etkili çözüm uygun özellikleri elde etmektir.

Seyrek Sütunlar


5
  1. Her veri türü için bir tane olmak üzere birden çok UDF tablosu oluşturun. Yani UDFStrings, UDFDates, vb. İçin tablolarımız olurdu. Muhtemelen # 2 ile aynı şeyi yapar ve yeni bir alan eklendiğinde otomatik olarak bir Görünüm oluşturur

Araştırmamıza göre veri türüne dayanan birden fazla tablo performans konusunda size yardımcı olmayacak. Özellikle 50+ UDF'li 20K veya 25K kayıtları gibi toplu verileriniz varsa. Performans en kötüydü.

Şunun gibi birden çok sütuna sahip tek bir tablo ile gitmelisiniz:

varchar Name
varchar Type
decimal NumberValue
varchar StringValue
date DateValue

Bu doğru ve onaylanmış olmalıdır. Phil tarafından 2011'de bir önceki cevap bugün 2016 için iyi bir tavsiye değil.
Yap Kai Lun Leon

Böyle bir işlem sql nasıl yapılacağını basit bir örnek alabilir miyim?
Niroj

Geç cevap için üzgünüm, ama aynı veritabanı yapısı istiyorum. Seni anlamadım @Niroj. İstediğiniz gibi ayrıntılı olarak açıklayabilir misiniz?
Amit Yüklenici

4

Bu sorunlu bir durum ve çözümlerin hiçbiri "doğru" görünmüyor. Ancak seçenek 1, hem basitlik hem de performans açısından muhtemelen en iyisidir.

Bu aynı zamanda bazı ticari işletme uygulamalarında kullanılan çözümdür.

DÜZENLE

şimdi mevcut olan, ancak soru asıl sorulduğunda mevcut olmayan (veya en azından olgun olmayan) başka bir seçenek de DB'deki json alanlarını kullanmaktır.

birçok ilişkisel DB artık json tabanlı alanları (alt alanların dinamik bir listesini içerebilir) destekler ve bunlarda sorgulamaya izin verir

postgres

mySQL


1
Yüzlerce kullanılmamış sütun oluşturma fikrinden nefret ediyorum. SQL veritabanı tasarımı hakkında öğrendiğim ve okuduğum şeylere aykırı. Şu anda, 1300'den fazla farklı kullanıcı tanımlı değere sahibiz, ancak birçoğu farklı şekilde adlandırılmış mevcut öğelerin kopyalarıdır.
Rachel

Tek bir masa için 1300 farklı UDF? her kullanıcının UDF veya sadece bir tür güçlü kullanıcı ekleme seçeneği var mı?
Ophir Yoktan

İçe aktarma işleminin bir parçası ... eşlenmemiş verileri kullanıcı tanımlı bir alana ekler. Hiç kimse, eşlenmemiş verileri mevcut UDF alanlarıyla eşleştirmek için zaman ayırmadığından, sadece yenilerini oluşturur ve yıllar boyunca çok şey eklenmiştir.
Rachel

2

Deneyim ya da 1, 3 ve 4 yaşadım ve hepsi ya dinamik ya da veriyi dinamik kayıt türlerine bölmek için bir tür yumuşak kategorizasyonla ne olduğu net değil.

XML denemek için cazip olurdu, UDF verilerinin fark kümelerini tutmaya yardımcı olacak veri yazımı vb kontrol etmek için xml içeriğine karşı şemaları zorlamak gerekir. SQL sunucusunun yeni sürümlerinde, performansa yardımcı olması gereken XML alanlarını endeksleyebilirsiniz. (bkz. http://blogs.technet.com/b/josebda/archive/2009/03/23/sql-server-2008-xml-indexing.aspx ) örneğin


Dürüst olmak gerekirse, XML'e hiç bakmadım. Bunun ana dezavantajı, nasıl çalıştığını ve buna karşı nasıl sorgulanacağını öğrenmek zorunda kaldım ve performansın diğer seçeneklerden daha kötü olabileceğini duydum
Rachel

1
Bunun için xml kullanmaktan kaçınırdım: işi yapabilir ve geçmişte xml'de böyle bir şey uyguladım, ancak veri yapıları büyüdükçe ve kod karmaşıklığı yüksek olduğu için performans oldukça kötüleşti.
Kell

2

SQL Server kullanıyorsanız, sqlvariant türünü göz ardı etmeyin. Oldukça hızlı ve işinizi yapmalı. Diğer veritabanlarında da benzer şeyler olabilir.

XML veri türleri performans nedenleriyle o kadar iyi değil. Eğer sunucuda hesaplamalar yapıyorsanız, sürekli olarak bunların serisini kaldırmanız gerekir.

Seçenek 1 kötü geliyor ve kabalık görünüyor, ancak performans açısından en iyi seçenek olabilir. Daha önce Field00-Field99 adlı sütunları olan tablolar oluşturdum çünkü performansı geçemezsiniz. INSERT performansınızı da dikkate almanız gerekebilir, bu durumda bu da gidilecek olanıdır. Düzgün görünmesini istiyorsanız, her zaman bu tabloda Görünümler oluşturabilirsiniz!


Teşekkürler, SQL varyantlarına tekrar bakacağım. En büyük endişem performans ve bunun nasıl ele alınacağından emin değilim, özellikle 50 milyondan fazla satırdan bahsediyorsak
Rachel

Sadece sql_varients LIKE yan tümcesi ile kullanılamaz öğrendim ... bu benim için büyük bir dezavantajı. Tabii ki, her UDF için bir görünüm oluşturursam, SQL_VARIANT_PROPERTY (değer, 'BaseType') tabanlı uygun veri tipine dökebilirdim ... yine de, performans için kötü gibi görünüyor
Rachel

LIKE kullanabilirsiniz, ancak önce değeri yayınlamanız gerekir. LIKE yalnızca varchar'larda çalışır, bu nedenle sql_variant'ınızı bir varchar'a atmanız gerekir. UDF'nizin bir varchar olup olmadığını bildiğiniz sürece (örneğin, tür başka bir yerde saklandığı için) tüm satırlarınızı varchar'lara filtreleyebilir, sonra LIKE sorgunuzu yayınlayabilir ve çalıştırabilirsiniz: örn. seçin * FROM MyTable burada variant_type = 'v' Cast (varchar olarak variant_value (max)) LIKE 'Blah%' Bu şekilde, ints ve benzeri öğeleri sizi yavaşlatacak dizelere dönüştürmüyorsunuz.
Tim Rogers

Özellikle milyonlarca satırda performansın nasıl olduğunu görmek için bazı testler yapmam gerekir. Sql_varients kullanarak performans hakkında çevrimiçi makaleler biliyor musunuz? Özellikle döküm ve çok sayıda kayıt ile?
Rachel


1

Ben geçmişte bu seçeneklerin hiçbirini (seçenek 6? :)) kullanarak çok başarılı bir şekilde başardım.

Ben kullanıcıların (xml olarak depolamak ve özel bir modelleme aracı ile ortaya çıkarmak) ve model oluşturulan tablolar ve görünümleri ile kullanıcı tanımlı veri tabloları ile temel tabloları katılmak için bir model oluşturmak. Böylece her türün temel verileri olan bir temel tablosu ve kullanıcı tanımlı alanları olan bir kullanıcı tablosu olacaktır.

Bir belgeyi örnek olarak alalım: tipik alanlar ad, tür, tarih, yazar vb. Olacaktır. Bu çekirdek tabloya gider. Daha sonra kullanıcılar kendi özel belge türlerini kontrat_end_tarihi, yenileme_çalışması, falan filan filan gibi kendi alanları ile tanımlarlar. Bu kullanıcı tanımlı belge için ortak bir birincil anahtarda birleştirilen çekirdek belge tablosu, xcontract tablosu olacaktır (bu nedenle xcontracts birincil anahtarı da çekirdek tablonun birincil anahtarında yabancıdır). Sonra bu iki tabloyu sarmak için bir görünüm oluşturur. Sorgulama sırasındaki performans hızlıydı. ek iş kuralları da görünümlere eklenebilir. Bu benim için gerçekten işe yaradı.


1

Veritabanımız, kullanıcıların 7k'tan fazla "özel alan" olduğu bir SaaS uygulamasına (yardım masası yazılımı) güç vermektedir. Birleşik bir yaklaşım kullanıyoruz:

  1. (EntityID, FieldID, Value)arama tablosuveri
  2. verileri görüntülemek için entitieskullanılan tüm varlık değerlerini tutan bir JSON alanı . (bu şekilde değer değerlerini elde etmek için bir milyon JOIN'a ihtiyacınız yoktur).

Bu cevabı gibi bir "veri türü başına tablo" elde etmek için # 1'i daha da bölebilirsiniz önerdiği , bu şekilde UDF'lerinizi dizine ekleyebilirsiniz.

PS "Varlık-Öznitelik-Değer" yaklaşımını savunmak için birkaç kelime herkes dayak tutar. # 1 olmadan # 1 yıllardır kullandık ve gayet iyi çalıştı. Bazen bu bir iş kararıdır. Uygulamanızı yeniden yazmak ve db'yi yeniden tasarlamak için zamanınız var mı veya bu günlerde gerçekten ucuz olan bulut sunucularına birkaç dolar atabilir misiniz? Bu arada, 1 numaralı yaklaşımı kullanırken, DB'miz 100 bin kullanıcı tarafından erişilen milyonlarca varlık tutuyordu ve 16GB'lık çift çekirdekli bir db sunucusu gayet iyi gidiyordu


Merhaba @Alex, benzer bir sorunla karşılaştım. İyi anlarsam: 1) custom_fields1 => last_concert_year, 2 => band, 3 => gibi değerleri depolayan bir tablo musicve ardından custom_fields_values001, 1, 1976 002, 1, 1977 003, 2, Iron Maiden003, 3 değerlerine sahip bir tablo , Metal Umarım örnek size mantıklıdır ve biçimlendirme için özür dileriz!
thitami

@thitami tam olarak değil. Aşağıdaki örnek: Bir var bandsbir sıra tablo 1,'Iron Maiden'ardından custom_fieldssatırlarla 1,'concert_year' | 2,'music'sonra custom_fields_valuessatırlarla1,1,'1977'|1,2,'metal'
Alex

0

Yorumlarda, UDF alanlarının kullanıcı tarafından düzgün şekilde eşlenmemiş olan içe aktarılan verileri dökmek olduğunu söyledim.

Belki de başka bir seçenek, her kullanıcı tarafından yapılan UDF'lerin sayısını takip etmek ve 6 (veya eşit derecede rastgele başka bir sınır) özel alan üstleri kullanabileceğini söyleyerek alanları tekrar kullanmaya zorlamaktır.

Bunun gibi bir veritabanı yapılandırma sorunu ile karşı karşıya kaldığınızda, uygulamanın temel tasarımına (sizin durumunuzdaki ithalat sistemi) geri dönüp üzerine birkaç kısıtlama koymak en iyisidir.

Şimdi ne yapacağım kullanıcılara bir bağlantı ekleyerek seçenek 4 (EDIT):

general_data_table
id
...


udfs_linked_table
id
general_data_id
udf_id


udfs_table
id
name
type
owner_id --> Use this to filter for the current user and limit their UDFs
string_link_id --> link table for string fields
int_link_id
type_link_id

Şimdi performansı optimize etmek ve indekslerinizi doğru hale getirmek için görünümler oluşturduğunuzdan emin olun. Bu normalleştirme düzeyi DB kapladığı alanı daha küçük hale getirir, ancak uygulamanız daha karmaşıktır.


0

Bu tür bir sistem, yüksek derecede akredite bir e-ticaret CMS platformu olan Magento'da kullanıldığından # 4'ü öneriyorum . FieldId & label sütunlarını kullanarak özel alanlarınızı tanımlamak için tek bir tablo kullanın . Sonra, her veri türü için ayrı tablolar var ve bu tabloların her birinde fieldId ve veri türü değer sütunlarına göre dizinler içeren bir dizin var . Ardından, sorgularınızda şöyle bir şey kullanın:

SELECT *
FROM FieldValues_Text
WHERE fieldId IN (
    SELECT fieldId FROM Fields WHERE userId=@userId
)
AND value LIKE '%' + @search + '%'

Bu, bence kullanıcı tanımlı türler için mümkün olan en iyi performansı sağlayacaktır.

Deneyimlerime göre, ayda milyonlarca kullanıcıya hizmet veren, özel ürün özelliklerine sahip binlerce ürüne ev sahipliği yapan ve veritabanı bile iş yükünü raporlama için bile kolayca işleyen birkaç Magento web sitesinde çalıştım.

Raporlama PIVOTiçin Alanlar tablosu etiket değerlerinizi sütun adlarına dönüştürmek için kullanabilir , ardından her bir veri türü tablosundaki sorgu sonuçlarınızı bu döndürülen sütunlara dönüştürebilirsiniz.

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.