Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Xитрый запрос в hql нужен (hibernate), Lazy-loading и все все 
:(
    Опции темы
chief39
Дата 4.2.2010, 18:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


карманная тигра
***


Профиль
Группа: Участник Клуба
Сообщений: 1631
Регистрация: 20.5.2005
Где: Киев

Репутация: 11
Всего: 77



Всем Арбуэ!

Такая штука интересная нужна в плане лейзи лоадинга(и не недогрузить и не перегрузить) и никак не вытанцовывается....

Суть вот в чём:

Данные:
Есть таблица InputData - это денормализованная таблица, которая содержит в себе записи из трёх сущностей. 
После процессинга она перебирается и распаковывается в  три таблицы: Amount, Account, Customer(эти самые сущности).

Соответственно, все они many-to-one (у кастомера много эккаунтов, а у эккаунтов много эмаунтов)
А вот InputData <-> Amount - один к одному (по сути, InputData - это Amount с довесками Account и Customer).

Что делаем:
Надо создать запись ReportData. Это таблица, которая содержит уже как бы аналитику на основе InputData данных.
Она Many-to-one к InputData и остальным этим таблицам (аналитики много и всякой).

Что мы делаем - мы делаем запрос, вытягиваем исходные данные из InputData и Amount(Account, Customer), вычисляем, записываем в
новенькую ReportData, линкуем её с имеющимися Amount, Account, Customer, InputData и записываем в БД.

Нюансы:
Эта группа(сей кусок аналитики) довольно большая. Просто физически вытянуть весь рекордсет не выйдет.
Поэтому пользуется iterate(), который пользует оракловый курсор.
А это означает прямой запрет JOIN FETCH :(

Работать должна довольно быстро. Поэтому подвыборки отметаются. Это долго. Должно хватать одного селекта.

Проблема:
Селект(чисто сгенерированый скльный, который идёт на нужды курсора) достаёт всё что надо...
Но потом хибернейт то слишком ленится, то слишком усердствует в инициализации объектов.

Здесь происходит создание ReportData,заполнение линков, данных и её save.
Комментами помечены строки где сетаются линки на объекты, которые мы вытянули своим запросом
Код

final ReportData rd = dataBuilder.createReportDataForSubtran(DataBuilder.GROUPING_11_64);
rd.setAmount(new BigDecimal(amount2).negate());
rd.setStatutoryCode(stc);
rd.setReportType(reportType);
rd.setInputRowAmount(amount); // lazy object
rd.setAccount(account); // lazy object
rd.setCustomer(customer); // lazy object
rd.setInputData(inputData); // lazy object
rd.setBank(bank);
rdd.save(rd);


Для всего этого мы используем примерно такой HQL запрос(234-й вариант smile ):
Код

SELECT ind, -- InputData object
ind.amountRow,  -- Amount object
am.account,  -- Account object
am.account.customer,  -- Customer object
ind.guaranteeType,  -- just a String
ind.creditorSector, -- just a String
ind.sectorCode, -- just a String
ind.amount2    -- just a BigDecimal
FROM InputData ind 
JOIN ind.amountRow am
WHERE ind.bank.id = ? 
AND ind.amountType = '120'
AND ind.origination <> 'MI'
AND ind.origination <> 'correction'
AND ind.ultimo <> true
AND ind.recordStatus = 3


Теперь что интересно... если InputData указать в select clause как am.inputDataRow - то в выборке этот объект фигурирует как NULL (!) Просто типа нету InputData и всё! Customer  Account - в наличии и здравии. Amount тоже. Конкретные поля из InputData тоже нормально вытянуты.. А вот объект InputData - отсуйствует.

Но если указать его явно по алиасу, типа: SELECT ind ... то он выбирается. Но тут же хибернейт запуливает туеву хучу сабселектов, которые тянут одиночными запросами InputDat'ы из базы. Это полностью сокрушает скорость.

Причём, такая лажа именно с объектом, который идёт первым после FROM. Если поменять запрос и отталкиваться от Amount - то будет такая же лажа с Amount вместо InputData

Генерит вот что(разные варианты были также):
Код

select 
inputdata0_.P_INPUT_DATA_OID as col_0_0_, inputdata0_.P_INPUT_DATA_OID as col_1_0_, amount1_.F_ACC_NUMBER as col_2_0_, 
account3_.F_CUSTOMER_ID as col_3_0_, inputdata0_.GUARANTEE_TYPE as col_4_0_, 
inputdata0_.CREDITOR_SECTOR as col_5_0_, inputdata0_.SECTOR as col_6_0_, inputdata0_.AMOUNT_2 as col_7_0_ 
from vos_statistics_200812.INPUT_DATA inputdata0_, vos_statistics_200812.AMOUNT amount1_, vos_statistics_200812.ACCOUNT account3_,
 vos_statistics_200812.CUSTOMER customer5_ 
where inputdata0_.P_INPUT_DATA_OID=amount1_.F_INPUT_DATA_ID and amount1_.F_ACC_NUMBER=account3_.P_ACC_OID 
and account3_.F_CUSTOMER_ID=customer5_.P_CUSTOMER_OID and inputdata0_.F_BANK_ID=? 
and inputdata0_.AMOUNT_TYPE='120' and inputdata0_.ORIGINATION<>'MI' and inputdata0_.ORIGINATION<>'correction' 
and inputdata0_.IS_ULTIMO<>1 and inputdata0_.RECORD_STATUS=3

Айдишки есть... Но объект-заглушку почему-то не создаёт  :(

Customer и Account прекрасно управляются только с айдишкой. Достал их, переложил в репортдату - сейв, готово. Остальные проперти мирно дрыхнут в БД.


Хочу просто доставать Amount и перекладывать в ReportData без всяких сабселектов...

Порезал много пропертей, которые будут запутывать. Если что - выложу остальные материалы для размышлизма по запросу.

Итак, как победить нашего "союзника, который облегчает нам жизнь"? smile



Код


<hibernate-mapping>
    <class name="com.edb.finance.product.bank.statistics.domain.Amount" table="AMOUNT" batch-size="50">
        <id name="id">
            <column name="P_AMOUNT_ROW_OID"/>
            <generator class="native"/>
        </id>
        <many-to-one name="account" class="com.edb.finance.product.bank.statistics.domain.Account" fetch="select">
            <column name="F_ACC_NUMBER" not-null="false">
                <comment>Reference to the account row</comment>
            </column>
        </many-to-one>
        <many-to-one name="inputData" class="com.edb.finance.product.bank.statistics.domain.InputData" column="F_INPUT_DATA_ID" unique="true" fetch="select"/>
    </class>
</hibernate-mapping>

<hibernate-mapping>
    <class name="com.edb.finance.product.bank.statistics.domain.InputData" table="INPUT_DATA" batch-size="50">
        <id name="id" >
            <column name="P_INPUT_DATA_OID"/>
            <generator class="increment"/>        </id>
        <one-to-one name="amountRow" class="com.edb.finance.product.bank.statistics.domain.Amount" property-ref="inputData" fetch="select"/>
    </class>
</hibernate-mapping>

<hibernate-mapping>
    <class name="com.edb.finance.product.bank.statistics.domain.Account" table="ACCOUNT">
        <id name="id">
            <column name="P_ACC_OID"/>
            <generator class="native"/>
        </id>
        <set name="amounts" inverse="true" lazy="true" fetch="select" >
           <key>
                <column name="F_ACC_NUMBER" not-null="false">
                    <comment></comment>
                </column>
            </key>
            <one-to-many class="com.edb.finance.product.bank.statistics.domain.Amount"/>
        </set>
    </class>
</hibernate-mapping>

<hibernate-mapping>
    <class name="com.edb.finance.product.bank.statistics.domain.Customer" table="CUSTOMER">
        <id name="id">
            <column name="P_CUSTOMER_OID"/>
            <generator class="native"/>
        </id>
        <set name="accounts" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="F_CUSTOMER_ID" not-null="false"/>
            </key>
            <one-to-many class="com.edb.finance.product.bank.statistics.domain.Account"/>
        </set>
    </class>
</hibernate-mapping>

<hibernate-mapping>
    <class name="com.edb.finance.product.bank.statistics.domain.ReportData" table="REPORT_DATA" batch-size="50">
        <id name="id">
            <column name="P_RPTD_OID" />
            <generator class="native"/>
        </id>
        <many-to-one name="inputData" class="com.edb.finance.product.bank.statistics.domain.InputData" fetch="select">
            <column name="F_INPUT_DATA_ID">
                <comment>Keep track to input data</comment>
            </column>
        </many-to-one>
        <many-to-one name="inputRowAmount" class="com.edb.finance.product.bank.statistics.domain.Amount" fetch="select">
            <column name="F_AMOUNT_ROW_OID" not-null="false">
                <comment>Keep track to Amount data</comment>
            </column>
        </many-to-one>        
        <many-to-one name="account" class="com.edb.finance.product.bank.statistics.domain.Account" fetch="select">
            <column name="F_ACC_NUMBER" not-null="false" />
        </many-to-one>
        <many-to-one name="customer" class="com.edb.finance.product.bank.statistics.domain.Customer" fetch="select">
            <column name="F_CUSTOMER_ID" not-null="false" />
        </many-to-one>
    </class>
</hibernate-mapping>







Это сообщение отредактировал(а) powerOn - 4.2.2010, 20:09


--------------------
Люди - это свечи. Они либо горят, либо их - в жопу!(с)

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java EE (J2EE) и Spring | Следующая тема »


 




[ Время генерации скрипта: 0.0396 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.