2012-03-01 3 views
3

Я пытаюсь немного оптимизировать таблицы базы данных. Но мое отсутствие понимания Hibernate/JPA сейчас не очень помогает.Как смешивать стратегии наследования в сочетании с несколькими слоями подкласса

У меня есть объектную модель Java, который выглядит более или менее, как это:

ParentClass 
    SubClass1 
    SubSubClass1 
    SubSubClass2 
    SubSubClass3 
    SubSubClass4 
    SubClass2 
    SubSubClass5 
    SubSubClass6 

Все классы содержат поля. Около 50% всех полей находятся в ParentClass. 40-50% находятся на уровне SubClass1 и 0-10% находятся на уровне SubSubclass. Многие классы SubSubClass * являются пустыми, но необходимы для идентификации Type.

TRY 1:

Зв Сначала мы использовали стратегию TABLE_PER_CLASS в Parentclass. Это привело к огромным количеством таблиц:

SubSubClass1 
SubSubClass2 
SubSubClass3 
SubSubClass4 
SubSubClass5 
SubSubClass6 

что не очень здорово, так как 50% всех столбцов в этих таблицах распределяются между всеми таблицами и другой Rest разделяется между 3-4 табл.

TRY 2:

Мы изменили стратегию SINGLE_TABLE.

Итоговый стол представляет собой только одну большую таблицу «ParentClass». Но так как только около 50% всех столбцов разделяются между всеми подклассами, для множества полей должно быть установлено значение Null, что не так сексуально.

TRY 3:

Следующая попытка была идти к смешению стратегии TABLE_PER_CLASS с "SINGLE_TABLE" Стратегией. Я решил не использовать JOIN TABLES в качестве стратегии, так как у меня есть много небольших подклассов, которые приведут к созданию множества небольших таблиц с одной или двумя столбцами внутри.

Итак, я следовал за ответы на этот вопрос: How to mix inheritance strategies with JPA annotations and Hibernate?

Я хотел теперь, чтобы поставить все значения из ParentClass в одной таблице, и все значения из первого подуровня в одну таблицу для каждого из них. Это должно привести к схеме, как это:

ParentClass 
- SubClass1 
- SubClass2 
- SubClass3 

Вот мой код:

@MappedSuperclass 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
public abstract class ParentClass { 
    private String value1; 
} 

@MappedSuperclass 
@SecondaryTable(name = "SubClass1") 
public abstract class SubClass1 extends ParentClass { 
    @Column(table = "SubClass1") 
    private String value11; 
} 

@MappedSuperclass 
@SecondaryTable(name = "SubClass2") 
public abstract class SubClass2 extends ParentClass { 
    @Column(table = "SubClass2") 
    private String value12; 
} 


@Entity 
@SecondaryTable(name = "SubClass1") 
public abstract class SubSubClass1 extends SubClass1 { 
    @Column(table = "SubClass1") 
    private String value111; 
} 

@Entity 
@SecondaryTable(name = "SubClass2") 
public abstract class SubSubClass2 extends SubClass2 { 
    @Column(table = "SubClass2") 
    private String value121; 
} 

Что на самом деле работает довольно хорошо. Но там мои проблемы начались:

Прежде всего, я получаю следующие ошибки во время SchemaUpdate.

Unsuccessful: alter table schema.SubClass1 add constraint AAAAAAA36D68C4 foreign key (id) references schema.ParentClass 
ORA-02275: such a referential constraint already exists in the table 

Unsuccessful: alter table schema.SubClass2 add constraint AAAAAAA36D68C4 foreign key (id) references schema.ParentClass 
ORA-02275: such a referential constraint already exists in the table 

Я думаю, что эти ошибки вызваны тем, что я использую SecondaryTables несколько раз на нескольких уровнях. Каждый раз, когда я их использую, создается другое ограничение. который, конечно, не работает, поскольку ограничение уже существует.

Вторая проблема заключается в том, что Hibernate сходит с ума, если он должен получать данные от всех этих таблиц:

select 
    * 
from 
    (select 
     parentclass0_.value1 as value1_1_, 
     parentclass0_1_.value11 as erste1_3_, 
     parentclass0_1_.value111 as value1113_3_, 
     parentclass0_2_.value12 as value122_3_, 
     parentclass0_2_.value121 as value1214_3_, 
     parentclass0_.DTYPE as DTYPE2_ 
    from 
     schema.parentclass parentclass0_ 
    left outer join 
     schema.subclass1 parentclass0_1_ 
      on parentclass0_.id=parentclass0_1_.id 
    left outer join 
     schema.subclass1 parentclass0_2_ 
      on parentclass0_.id=parentclass0_2_.id 
    left outer join 
     schema.subclass1 parentclass0_3_ 
      on parentclass0_.id=parentclass0_3_.id 
    left outer join 
     schema.subclass2 parentclass0_4_ 
      on parentclass0_.id=parentclass0_4_.parentclass_id 
    left outer join 
     schema.subclass1 parentclass0_5_ 
      on parentclass0_.id=parentclass0_5_.id 
    left outer join 
     schema.subclass1 parentclass0_6_ 
      on parentclass0_.id=parentclass0_6_.id) 

Она соединяет ту же таблицу для каждого времени я использовал @SecondaryTable аннотацию в подклассе. Он присоединяется к нему снова и снова. Я взглянул на план объяснения Oracle, который говорит мне, что этот план автоматически оптимизируется для того, что я буду использовать, если бы я его оптимизировал. но в любом случае. Странно.

Вопрос:

Как я могу предотвратить Hibernate от создания же ограничений несколько раз? Я думаю, что это также устранит проблему соединения. Или должен перестать пытаться сделать это так и есть другой путь?

ответ

2

Я думаю, что вы действительно должны использовать стратегию SINGLE_TABLE. 50% разделяемых столбцов ДЕЙСТВИТЕЛЬНО не так уж плохи, особенно если вы знаете, что число со временем не будет уменьшаться (я имею в виду, что, как вы думаете, в один прекрасный день в этой таблице будет 500 столбцов, причем всего по 40 столбцов?) И если вы собираетесь запускать много запросов против корневого объекта, который всегда будет делать много соединений с другой стратегией.

На работе мы только что обсуждали это. Стратегия SINGLE_TABLE была выбрана потому, что мы не думали, что количество столбцов будет взрываться, и мы можем завершить только 5% общих свойств :(Поэтому я думаю, что это будет работать на ваше дело, но позаботьтесь и подумайте, как ваши данные к которому будет обращаться.

Редактирование: так как невозможно смешивать стратегии, и вам не нужно много таблиц: Если у вас есть 140 сущностей и 50% общих атрибутов, вы действительно должны ДЕЙСТВИТЕЛЬНО использовать стратегию SINGLE_TABLE! !!!!!

+0

Мы закончили использование стратегии SINGLE_TABLE. Анализ SQL-запросов показал огромный выигрыш в эффективности. Одна таблица заставляет запрос иметь стоимость 6. Каждая добавленная таблица добавляет 1 Стоимость. При полномасштабном объединении таблицы таблиц мы получим более 150 таблиц, что приведет к 160 стоимости.что в 26 раз больше, чем у одной таблицы. Мы думаем, что мы будем смешивать некоторые вспомогательные таблицы для оптимизации некоторых частей кода. Тесты показали, что это очень аккуратно и не вызывает много проблем, кроме тех, которые я упомянул в своем вопросе (который можно устранить или игнорировать) – user932708

0

Почему вы не используете стратегию JOINED в родительском классе? У вас все равно будет много таблиц, но нет избыточных атрибутов.

+0

Вы только что упоминали мой ответ: для многих таблиц. База данных должна использоваться другими технологиями, которые не используют модель данных Java. Для этой цели наша цель - сократить количество таблиц до справедливой счет, который находится между подходом к одной таблице и СОЕДИНЕННЫМ подход. Одна таблица вызовет 1 таблицу. JOINED приведет к появлению около 140 таблиц. Наш запланированный подход привел бы к 1 мастер-таблице + 6 подтекстов – user932708

8

С точки зрения JPA, вы НЕ МОЖЕТЕ СМЕШАТЬ стратегии в дереве наследования. Цитирую спецификации JPA (11.1.20)

Наследование аннотаций определяет стратегию наследования, которая будет использоваться для иерархии классов сущности. Он указан в классе сущности , который является корнем иерархии классов сущностей. Поддержка этой комбинации стратегий наследования не требуется этой спецификацией. Переносимые приложения должны использовать только одну стратегию наследования в иерархии сущности.

JDO - единственная спецификация устойчивости, которая позволяет вам определять различные стратегии по дереву.

+0

Ну .. несчастный ответ правильный :) – user932708

Смежные вопросы