使用鉴别器时避免使用SELECT + 1

时间:2012-02-06 16:09:15

标签: nhibernate fluent-nhibernate

我正在使用鉴别器来处理项目状态。我正在使用NHibernate Profiler并注意到我的应用程序在选择我的状态方面变得非常疯狂。我总共有8个状态,NHibernate一直在查询:

SELECT state0_.State_id         as State1_10_0_,
       state0_.Name             as Name10_0_
FROM   States state0_
WHERE  state0_.State_id = **3** /* @p0 */

当我选择状态为例如等于1,2,3,4或5的所有项时,触发此SELECT + 1的是什么。这将为我的项发出一个查询以及为每个状态发出5个查询。由于我经常查询项目(有状态),我正在执行大量的查询。

现在,看一下分析器,我不确定这是一个很大的问题,因为我查询的第一个状态需要6ms才能查询,6ms需要实现。所有其他状态显示为0ms查询和0ms实现。 NHibernate Profiler仍然将其显示为臭名昭着的SELECT + 1问题。

根据我的聚合根映射,我有:

        References(x => x.State)
            .Not.Nullable()
            .Not.LazyLoad();

对于我的状态鉴别器映射,我有:

        Id(x => x.Id, "State_id").GeneratedBy.Assigned();
        Map(x => x.Name).Not.Nullable();

        DiscriminateSubClassesOnColumn("State_id");

是否有一些我不了解歧视者的事情?

以下是导致问题的查询:

var items =
    session.QueryOver(() => itemAlias)
        .SelectList(x => x
                             .Select(xx => xx.Id).WithAlias(() => sentTo.Id)
                             .Select(xx => xx.State).WithAlias(() => sentTo.State)
                             .Select(xx => xx.Status).WithAlias(() => sentTo.Status)
        )
        .JoinAlias(() => itemAlias.State, () => stateAlias)
        .WhereRestrictionOn(() => stateAlias.Id).IsInG(filters)
        .Where(() => itemAlias.Status == Status.InProgress)
        .TransformUsing(Transformers.AliasToBean<SentToDto>())
        .List<SentToDto>();

解决方案

罪魁祸首是

.WhereRestrictionOn(() => stateAlias.Id).IsInG(filters)

要解决我的SELECT + 1问题,我只需要通过一个鉴别器对象列表来查询,而不是单个id。

.Where(() => itemAlias.State.IsIn(new []{State.FooState, State.BarState}))

1 个答案:

答案 0 :(得分:1)

听起来你急于加载状态本身,所以你的第一个查询是这样的:

SELECT * FROM Items where StateID IN (1,2,3,4,5)

然后,每个州有五个查询:

SELECT Name FROM State WHERE StateID = 1
SELECT Name FROM State WHERE StateID = 2
....

这样做是为了急切加载状态的名称,所以为了避免它,你应该在第一个查询中指定从“items”到“states”的连接,这样你就可以在那里获得名称,否则设置State对象如果您不需要除结果中的标识符之外的其他信息,则延迟加载。