更新: 我错误地从错误的重载中粘贴了查询代码。底部是固定代码
嗨,我们说这是我的域名。
我正在跟踪一些体育赛事,比如赛车比赛。
每场比赛都有参加比赛的赛车手。
Racer特别是Race的驱动程序(它有Driver,start lane,run-time等)。
驱动程序包含名称等等......典型的个人数据。
我想做以下查询: 在本次活动中,让我参加所有比赛(让我们分页),向参赛者展示信息,包括从车手那里获取的数据。
我的问题是,我不认为我的映射(或标准查询,或两者)对于这种情况是最佳的,所以我想问你,如果你在这里看到任何优化机会。 我特别不喜欢这样一个事实,即当我认为子查询可以让它一次性工作时,它需要两次往返数据库。
这是我的映射和查询(DB是从映射生成的)
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Foo"
namespace="Foo">
<class name="Event" table="Events">
<id name="Id">
<generator class="guid"/>
</id>
<property name="EventId" not-null="true" unique="true" index="IDX_EventId" />
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Foo"
namespace="Foo">
<class name="Race" table="Races">
<id name="Id">
<generator class="guid"/>
</id>
<property name="RaceId" not-null="true" unique="true" index="IDX_RaceId"/>
<property name="Year" not-null="true" />
<property name="IsValid" not-null="true" />
<property name="Time" not-null="true" />
<many-to-one name="Event" cascade="all" not-null="true" />
<bag name="Contestants" cascade="save-update" inverse="true" lazy="false" batch-size="20" >
<key column="Race"/>
<one-to-many class="Racer"/>
</bag>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Foo"
namespace="Foo">
<class name="Racer" table="Racers">
<id name="Id">
<generator class="guid"/>
</id>
<many-to-one name="Race" foreign-key="FK_Racer_has_race" not-null="true" cascade="save-update" />
<property name="Lane" not-null="true" />
<many-to-one name="Driver" foreign-key="FK_Racer_has_driver" cascade="save-update" lazy="false" fetch="join" />
<property name="FinishPosition" />
<property name="Finished" not-null="true" />
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Foo"
namespace="Foo">
<class name="Driver" table="Drivers">
<id name="Id">
<generator class="hilo"/>
</id>
<property name="Name" not-null="true" length="32" unique="true" index="IDX_Driver_Name" />
</class>
</hibernate-mapping>
查询代码:
public IList<Race> GetMostRecentRacesForEvent( int eventId, int firstRaceToFetch, int count ) {
DetachedCriteria criteria = DetachedCriteria.For( typeof( Race ) ).
CreateAlias( "Event", "event" ).
Add( Restrictions.Eq( "event.EventId", eventId ) ).
AddOrder<Race>( r => r.Time, Order.Desc ).
SetResultTransformer( new DistinctRootEntityResultTransformer() ).
SetFirstResult( firstRaceToFetch ).
SetMaxResults( count );
return this.ExecuteListQuery<Race>(criteria); }
将分页设置为3个比赛/页,这是它生成的SQL:
SELECT TOP 3 Id2_1_, RaceId2_1_, Year2_1_, IsValid2_1_, Time2_1_, Event2_1_, Id1_0_, EventId1_0_ FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_0__ DESC) as row, query.Id2_1_, query.RaceId2_1_, query.Year2_1_, query.IsValid2_1_, query.Time2_1_, query.Event2_1_, query.Id1_0_, query.EventId1_0_, query.__hibernate_sort_expr_0__ FROM (SELECT this_.Id as Id2_1_, this_.RaceId as RaceId2_1_, this_.Year as Year2_1_, this_.IsValid as IsValid2_1_, this_.Time as Time2_1_, this_.Event as Event2_1_, event1_.Id as Id1_0_, event1_.EventId as EventId1_0_, this_.Time as __hibernate_sort_expr_0__ FROM Races this_ inner join Events event1_ on this_.Event=event1_.Id WHERE event1_.EventId = @p0) query ) page WHERE page.row > 0 ORDER BY __hibernate_sort_expr_0__ DESC
第二次查询:
SELECT contestant0_.Race as Race2_,
contestant0_.Id as Id2_,
contestant0_.Id as Id0_1_,
contestant0_.Race as Race0_1_,
contestant0_.Lane as Lane0_1_,
contestant0_.Driver as Driver0_1_,
contestant0_.FinishPosition as FinishPo5_0_1_,
contestant0_.Finished as Finished0_1_,
driver1_.Id as Id3_0_,
driver1_.Name as Name3_0_
FROM Racers contestant0_
left outer join Drivers driver1_
on contestant0_.Driver = driver1_.Id
WHERE contestant0_.Race in ('4157280d-be8d-44be-8077-a770ef7cd394' /* @p0 */,'74e1bfaa-9926-43c7-8b17-e242634dc32f' /* @p1 */,'e1e86b67-2c37-4fbe-8793-21e84a6e4be4' /* @p2 */)
答案 0 :(得分:1)
Stefan(退出评论,因为此时此功能已变得不太可用)。
我根据你的建议重新编写代码(不改变任何映射)现在,查询只返回一个Race - 三个中的第一个(分页设置为3个比赛/页)与查询匹配。
当我删除
时SetResultTransformer( new DistinctRootEntityResultTransformer() )
我得到三个项目,但是它的值是三次相同的值,这很奇怪。有什么想法吗?
答案 1 :(得分:1)
我认为它会创建多个查询,以避免重复进入分页查询。 (但我不确定,我还没有看到nhibernate内部源代码)。对包含用于获取实体的重复项的集合进行分页,因为使用了连接实际上是无用的,因此您需要确保返回的结果集没有重复。我认为nhibernate选择2个或更多查询而不是1个查询。
答案 2 :(得分:0)
试试这个:
DetachedCriteria criteria = DetachedCriteria.For( typeof( Race ), "race" )
.CreateAlias("Event", "event")
.CreateAlias("race.Contestants", "contestant")
.SetFetchMode("race.Contestants", FetchMode.Join)
.SetFetchMode("contestant.Driver", FetchMode.Join)
.Add( Restrictions.Eq( "event.EventId", eventId ) )
.AddOrder<Race>( r => r.Time, Order.Desc )
.SetResultTransformer( new DistinctRootEntityResultTransformer() )
.SetFirstResult( firstRaceToFetch )
.SetMaxResults( count );
return this.ExecuteListQuery<Race>(criteria); }
它应该进行单个查询并加入比赛,赛事和参赛者。
你不应该使用FetchMode.Join太多,返回的结果集更大。 (它包括种族和活动信息,与参赛者一样多次。)