2010-01-07 11 views
13

Hazırda bekletilen bir sınıf hiyerarşisi için tablo düzenini düşünüyorum ve kesinlikle alt sınıf tekniği için tablo genel anlamda en uygun olanı vurur. Ancak, mantık yoluyla düşünmek, özellikle alt sınıflar ölçeğinin sayısıyla ilgili bazı kaygılarım var. Hibernate'in tablo başına alt sınıf miras stratejisinin verimliliği

en aşağıdaki sınıfları var diyelim, çok kısa (ve klasik) örnek vermek gerekirse:

public abstract class Animal { 
    int pkey; 
    String name; 
} 

public class Dog extends Animal { 
    long numSlippersChewed; // int is not large enough... 
} 

public class Cat extends Animal { 
    short miceCaught; // ... but here int is far bigger than required :-) 
} 

(ı eliding ediyorum Alıcılar ve ayarlayıcılar vb eşleştirmeleri Hazırda, sadece onların farz ediyorum temel açık durum).

Bu varlıklar için veritabanı tabloları mantıklı, güzel denormalizasyon ve benzeri. Bununla birlikte, bireysel bir hayvanı çıkarmak için Hibernate hangi sorguyu yapıyor? Bunun gerçekleşebilir en az iki olgu düşünebilirsiniz:

  1. böyle bir Human sınıfın bir pet alanı olarak bire-bir (veya bire çok) eşleştirmesini sahip diğer bazı varlık. Bu, payı saklayacaktır, bu yüzden Hazırda Bekletme, bir Human nesnesini getirdiğinde, ilgili Animal nesnesini de getirmelidir. Hayvanın pkeyini verildiğinde, hangi sorgu (/ ies), Cat veya Dog tablolarında yer alabildiği göz önüne alındığında, gerçek Hayvan verilerini ayıklamak ve unshashall için kullanımı hazırda tutar mı? from Animal where name='Rex' gibi HQL gibi
  2. HQL (isimlerin benzersiz olduğunu varsayalım). Bu, üst sınıf tablosunda bir satırı tanımlamanıza olanak tanıyan, ancak daha fazla ayrıntı için incelemek üzere hangi alt sınıfı tabloyu bildiğinizi bilmediğinize benzer. HQL, bir sorguyu from soyut bir sınıf oluşturmanıza izin veriyor mu? (Alt sınıflara özgü şeyleri kullanmak güzel olsa da, örneğin, from Cat where miceCaught > 5).

Bunun SQL'de yapılabileceğini iki şekilde düşünebilirim ve ne güzel görünüyorlar. Biri, verilen pkey için her bir alt sınıf tablosunda bir exists sorgusunu çalıştırmak ve daha sonra bir isabet döndüren tablodan yüklemek. Alternatif olarak Hazırda Bekletme, tüm tablolarda bir araya gelen bazı korkunç sendika sorgularını gerçekleştirebilir - temel olarak, sonuç kümesinin, bağımsız değişkenler için null döndüren alt sınıf tablolarından tek tek seçildiği olası alt sınıfların niteliklerini içereceği şekilde, tablo başına hiyerarşi şemasını simüle edebilir. Bu ikinci durumda muhtemelen bir sentetik diskriminatör kolonu eklemesi gerekecek, böylece Hazırda Bekletme hangi alt sınıf tablosunun gerçekten satırı döndürdüğünü ve böylelikle hangi Java sınıfının ayrıştırıldığını bilecektir.


şeyler somut tiplerinin alt türlerini sahip çok olursa hairier olsun: Belirli bir hayvan pkey Şimdi

public class Greyhound extends Dog { 
    float lifetimeRacingWinnings; 
} 

, yani Dog ve Greyhound tablolarda geçerli satırlar olabilir benim Bir pkeye karşılık gelen sınıfı manuel olarak kontrol etmenin ilk yaklaşımı daha da zorlaşır.

Çok endişelenmemin nedeni, bu yaklaşımı en fazla 4-5 seviyeli yuvalama zinciri ile yaklaşık 70 sınıfa sahip bir sınıf hiyerarşisinde kullanmak isteyeceğim olmasıdır. korkunç performansına sahip olması muhtemel. Hibernate'in bu nispeten daha iyi performans göstermesini sağlamak için manşetinin herhangi bir numarası var mı? Ya da pkey tarafından uzun bir zaman alacak olan bu sınıflardan birine referans yükleniyor?

+0

Belki de http://stackoverflow.com/questions/2700680/table-per-subclass-inheritance-relationship-how-to-query-against-the-parent-clas adresini görmek istersiniz –

+0

Merak ediyorum. Bazı diğer JPA Nesne tabanlı depolama sistemleri aynı soruna (yani ObjectDB) sahiptir. Başka bir deyişle, standart bir ilişkisel veritabanı, özellikle büyük bir nesne grafiğinize sahip olduğunuzdan, en iyi teknoloji olmayabilir. –

cevap

8

Hazırda bekletme, bilinmeyen bir hayvan türü için sorguyu, her bir alt sınıf için bir dizi LEFT JOIN yazısıyla yazıyor. Bu yüzden, alt sınıfların sayısı arttıkça sorgu yavaşlayacak ve daha geniş bir sonuç kümesine dönmeye çalışacaktır. Yani siz haklısınız, büyük sınıf hiyerarşileriyle iyi ölçeklenmiyor.

HQL ile, evet, doğrudan alt sınıfı sorgulayabilir ve özelliklerine erişebilirsiniz. Bu daha sonra tek bir INNER JOIN ile işlenecektir.

Bunu birden fazla kalıtım düzeyiyle denemedim. Yukarıdakiler sizi henüz kapatmamışsa, bunu denemenizi ve görmenizi öneririz. Veritabanına gönderilenleri görmek için SQL hata ayıklama çıktısını açabilir veya veritabanınızı profilleyebilirsiniz.

+0

Teşekkürler - Kendimi test etmeyi düşündüm, ancak bir nedenden dolayı performans testi için gerçekçi bir veri kütlesinin olmazsa olmaz olduğunu düşünmemiştim ve endişelerimle bu şekilde gelişmeye başlamak istemedim. Bununla birlikte, sahte bir test vakasının, en azından kullanılan teknikleri görmeme izin verecek ve bunu bir Hazırda Bekletme performans sorusundan bir SQL performans sorusuna indirgeyecek, bu da akılda tutulması çok daha kolay olmalıdır. –

+0

Üçüncü paragrafınıza başvurmak: Gönderdiğim SQL'in gösterdiği gibi, birden fazla kalıtım düzeyi çok fazla değişmiyor. Anlayabildiğim kadarıyla, tek fark, sentetik bir discriminator üretmek için kullanılan 'case' ifadesindeki cümlelerin sırasını ifade etmektir. Yani kesinlikle bir performans açısından bu aynı olmalıdır. (Tabii ki, bir alt sınıfı somut olarak ortaya koyarken, ama beni çok fazla ilgilendirmeyen daha fazla tablo olacak). –

+0

Yansımadan bu yana kabul edildi olarak işaretlemek, ümit ettiğim sihirli mermiyi sağlamadığı halde, sorduğum soruyu açıkça yanıtlıyor. –

3

David M's helpful answer'dan sonra bir iskelet testi yapmaya karar verdim.

Üç düzey bir hiyerarşide soyut bir üst sınıf, ADTestA ve 25 alt altsınıf oluşturdum (Adlarını tahmin etmenizi bekliyorum). Her bir sınıf, mektubuna karşılık gelen bir ad ile bir tek tamsayı alanına sahipti - örneğin, sınıfına ait 012112864985911924925911510101 alanına ek olarak, sınıfının tek bir int alanı da alanı ve pkey ve a alanları en üstteki alanından devralır. -level soyut süper sınıfı. HQL sorgusu from ADTestA where pkey=1 Verme

aşağıdaki SQL sonuçlandı:

çok hoş değil, ben önlenebileceği umut başına hiyerarşinin tablosunun etkili simülasyonuna karşılık vermez
select adtesta0_.pkey as pkey0_, adtesta0_.a as a0_, adtesta0_1_.b as b1_, 
     adtesta0_2_.c as c2_, adtesta0_3_.d as d3_, adtesta0_4_.e as e4_, 
     adtesta0_5_.f as f5_, adtesta0_6_.g as g6_, adtesta0_7_.h as h7_, 
     adtesta0_8_.i as i8_, adtesta0_9_.j as j9_, adtesta0_10_.k as k10_, 
     adtesta0_11_.l as l11_, adtesta0_12_.m as m12_, adtesta0_13_.n as n13_, 
     adtesta0_14_.o as o14_, adtesta0_15_.p as p15_, adtesta0_16_.q as q16_, 
     adtesta0_17_.r as r17_, adtesta0_18_.s as s18_, adtesta0_19_.t as t19_, 
     adtesta0_20_.u as u20_, adtesta0_21_.v as v21_, adtesta0_22_.w as w22_, 
     adtesta0_23_.x as x23_, adtesta0_24_.y as y24_, adtesta0_25_.z as z25_, 
     case 
      when adtesta0_6_.pkey is not null then 6 
      when adtesta0_7_.pkey is not null then 7 
      when adtesta0_8_.pkey is not null then 8 
      when adtesta0_9_.pkey is not null then 9 
      when adtesta0_10_.pkey is not null then 10 
      when adtesta0_11_.pkey is not null then 11 
      when adtesta0_12_.pkey is not null then 12 
      when adtesta0_13_.pkey is not null then 13 
      when adtesta0_14_.pkey is not null then 14 
      when adtesta0_15_.pkey is not null then 15 
      when adtesta0_16_.pkey is not null then 16 
      when adtesta0_17_.pkey is not null then 17 
      when adtesta0_18_.pkey is not null then 18 
      when adtesta0_19_.pkey is not null then 19 
      when adtesta0_20_.pkey is not null then 20 
      when adtesta0_21_.pkey is not null then 21 
      when adtesta0_22_.pkey is not null then 22 
      when adtesta0_23_.pkey is not null then 23 
      when adtesta0_24_.pkey is not null then 24 
      when adtesta0_25_.pkey is not null then 25 
      when adtesta0_1_.pkey is not null then 1 
      when adtesta0_2_.pkey is not null then 2 
      when adtesta0_3_.pkey is not null then 3 
      when adtesta0_4_.pkey is not null then 4 
      when adtesta0_5_.pkey is not null then 5 
      when adtesta0_.pkey is not null then 0 
     end as clazz_ 
from ADTestA adtesta0_ 
      left outer join ADTestB adtesta0_1_ on adtesta0_.pkey=adtesta0_1_.pkey 
      left outer join ADTestC adtesta0_2_ on adtesta0_.pkey=adtesta0_2_.pkey 
      left outer join ADTestD adtesta0_3_ on adtesta0_.pkey=adtesta0_3_.pkey 
      left outer join ADTestE adtesta0_4_ on adtesta0_.pkey=adtesta0_4_.pkey 
      left outer join ADTestF adtesta0_5_ on adtesta0_.pkey=adtesta0_5_.pkey 
      left outer join ADTestG adtesta0_6_ on adtesta0_.pkey=adtesta0_6_.pkey 
      left outer join ADTestH adtesta0_7_ on adtesta0_.pkey=adtesta0_7_.pkey 
      left outer join ADTestI adtesta0_8_ on adtesta0_.pkey=adtesta0_8_.pkey 
      left outer join ADTestJ adtesta0_9_ on adtesta0_.pkey=adtesta0_9_.pkey 
      left outer join ADTestK adtesta0_10_ on adtesta0_.pkey=adtesta0_10_.pkey 
      left outer join ADTestL adtesta0_11_ on adtesta0_.pkey=adtesta0_11_.pkey 
      left outer join ADTestM adtesta0_12_ on adtesta0_.pkey=adtesta0_12_.pkey 
      left outer join ADTestN adtesta0_13_ on adtesta0_.pkey=adtesta0_13_.pkey 
      left outer join ADTestO adtesta0_14_ on adtesta0_.pkey=adtesta0_14_.pkey 
      left outer join ADTestP adtesta0_15_ on adtesta0_.pkey=adtesta0_15_.pkey 
      left outer join ADTestQ adtesta0_16_ on adtesta0_.pkey=adtesta0_16_.pkey 
      left outer join ADTestR adtesta0_17_ on adtesta0_.pkey=adtesta0_17_.pkey 
      left outer join ADTestS adtesta0_18_ on adtesta0_.pkey=adtesta0_18_.pkey 
      left outer join ADTestT adtesta0_19_ on adtesta0_.pkey=adtesta0_19_.pkey 
      left outer join ADTestU adtesta0_20_ on adtesta0_.pkey=adtesta0_20_.pkey 
      left outer join ADTestV adtesta0_21_ on adtesta0_.pkey=adtesta0_21_.pkey 
      left outer join ADTestW adtesta0_22_ on adtesta0_.pkey=adtesta0_22_.pkey 
      left outer join ADTestX adtesta0_23_ on adtesta0_.pkey=adtesta0_23_.pkey 
      left outer join ADTestY adtesta0_24_ on adtesta0_.pkey=adtesta0_24_.pkey 
      left outer join ADTestZ adtesta0_25_ on adtesta0_.pkey=adtesta0_25_.pkey 
where adtesta0_.pkey=1 

.

Bu tür sorguların çok pahalı olacağı anlaşılıyor. Ne sıklıkta ihtiyaç duyulacağına dair bir düşünceme sahip olacağım (bir örnekte ADTestP örneğini istediğimi bildiğimden ve bu haklardan bir tanesinin yalnızca gerekli üst tablolarda yer alan birinden istendiğini bilmek). Bununla birlikte, bunun taraflardan gelen referanslarla kaçınılmaz olacağını düşünüyorum; Diğer bir deyişle, ADTestA türündeki bir alandan bire bir eşleme, her zaman tam olarak bu tür bir aramayı içerecektir.

(Öte yandan, alternatif stratejiler ya umut işaretleri değil, hiyerarşi tablosunun gidişini ve tam anlamıyla yüzlerce sütunları tek bir tabloya yerleştirmek çok verimli gelmiyor ...)

+0

+1 - teşekkürler. –

1

DB'nize yalnızca Hazırda Bekletme aracılığıyla eriştiğiniz sürece ve ya önemli verileriniz yoksa veya küçük bir geçiş komut dosyası yazmaya hazır olduğunuz sürece, geliştirme sürecinizdeki alt sınıf/hiyerarşide tablo hakkında karar verebilmeniz gerekir. süreci. Bu bir ORM güzelliği, bu veritabanı yapısı soyut ...

Diğer taraftan, "miras üzerinde kompozisyon tercih" (Prefer composition over inheritance?) büyük bir hayranıyım ve ben bir model 70 ile oldukça şüpheli değilim 4-5 seviyeleri arasındaki sınıflar basitleştirilemez ... ama bunun üzerinde kendiniz için düşünmenize izin vereceğim, sonuçta ne tür bir probleme sahip olmaya çalıştığınızı bilmiyorum.

+0

Maalesef masalar * esasen Hazırda Bekletme yoluyla erişilecek, ancak tasarımın diğer Java dışı araçlar için zaman zaman erişmesi için en azından aklı başında olması gerekir. Buradaki kaygıların ilgisini karıştırıyor olabilirim, ancak sınıf hiyerarşisi yeni bir tablonun tanıtımıyla aynı zamanda yeniden başlıyor ve DB performansı birincil motivasyonlardan biri. Soyutlama konusunu bir dereceye kadar kabul ediyorum ama Joel soyutlama sızıntısı yazarken; Bunu Hazırda bekletme modunda yapmak mümkün değilse, bunu mümkün olduğunca erken bir zamanda keşfetmem gerekiyor. –

+0

Oh - ve meşru olan alt sınıfların sayısı hakkında bir feragatname yazmayı düşünmüştüm, çünkü birinin bir koku olarak vurgulayacağını düşündüm. :-) Hayvan benzetmesi devam ediyor, ben bir hayvanat bahçesi ya da veterinere benzer bir şey için kod yazıyorum, bu yüzden meşru bir 'Hayvan'> Omurgalıların> Memeli'> Carnivore> Canine'> Dog' türüne sahibiz hiyerarşi, birçok farklı hayvan için (ve evet, hiyerarşinin her düzeyinde yararlı bir davranış var). Java kodu, bu sınıf yapısında yerini aldığı neredeyse düz olandan çok daha güzel ve daha temizdir. –