NHibernate - 联盟三个QueryOvers

时间:2012-10-03 11:18:25

标签: nhibernate queryover

您好StackOverflow用户,

我遇到了这个问题 我有三个QueryOvers,每个QueryOvers返回一个候选ID列表,然后我用它来带来这些候选者。 为此我写了下面的代码。

        private IQueryOver<CandidateEntity, CandidateEntity> UnionPublicWithPrivateCandidates(
        IQueryOver<CandidateEntity, CandidateEntity> publicCandidates, 
        IQueryOver<CandidateEntity, CandidateEntity> privateCandidate, 
        IQueryOver<CandidateEntity, CandidateEntity> candidatesByUserRole)
    {
        return ActiveCandidatesQueryOver.Where(Restrictions.Disjunction()
                                        .Add(Subqueries
                                            .WhereProperty<CandidateEntity>(c => c.Id)
                                            .In((QueryOver<CandidateEntity>)publicCandidates.Select(c => c.Id)))
                                        .Add(Subqueries
                                            .WhereProperty<CandidateEntity>(c => c.Id)
                                            .In((QueryOver<CandidateEntity>)privateCandidate.Select(c => c.Id)))
                                        .Add(Subqueries
                                            .WhereProperty<CandidateEntity>(c => c.Id)
                                            .In((QueryOver<CandidateEntity>)candidatesByUserRole.Select(c => c.Id))));
    }

返回正确的结果,生成的查询如下所示

SELECT *
FROM   Applicants 
WHERE  IsActive = 1
   and (Id in (SELECT Id from **FirstQueryOver**)
         **or** Id in (SELECT Id from **SecondQueryOver**)
         **or** Id in (SELECT Id from **ThirdQueryOver**))

问题是它使用'或'。因此,查询速度非常缓慢。

如果我写这个:

SELECT *
FROM   Applicants 
WHERE  IsActive = 1
   and (Id in (SELECT Id from **FirstQueryOver**
                     union SELECT Id from **SecondQueryOver**
                     union SELECT Id from **ThirdQueryOver**))

它几乎立即完成。

您是否知道如何重构代码以获得更好的性能?

谢谢你, 阿德里安。

2 个答案:

答案 0 :(得分:1)

我搜索但没有找到任何东西,所以我做了以下黑客攻击:

private IQueryOver<CandidateEntity, CandidateEntity> UnionPublicWithPrivateCandidates(
                  IQueryOver<CandidateEntity, CandidateEntity> publicCandidates,
                  IQueryOver<CandidateEntity, CandidateEntity> privateCandidate,
                  IQueryOver<CandidateEntity, CandidateEntity> candidatesByUserRole)
{
    var excludedQueryCandidates = QueryOver
        .WithSubquery.WhereNotExists(((QueryOver<CandidateEntity>)publicCandidates.Select(x => x.Id)))
        .WithSubquery.WhereNotExists((QueryOver<CandidateEntity>)privateCandidate.Select(x => x.Id))
        .WithSubquery.WhereNotExists((QueryOver<CandidateEntity>)candidatesByUserRole.Select(x => x.Id));

    return QueryOver.WithSubquery.WhereNotExists((QueryOver<CandidateEntity>) excludedQueryCandidates.Select(Projections.Distinct(Projections.Id())));
}

这不是最佳解决方案,但应该有效。

答案 1 :(得分:0)

我不能说为什么联盟或联盟有这样的差异。 sql探查器,查询分析器和估计的执行计划应该让你更深入地了解sql运行查询的内容,我猜它在第一种情况下没有使用正确的索引。但是,我会尝试将您的查询重写为:

SELECT *
  FROM   Applicants  
  WHERE  IsActive = 1
    and (this_.Id in (SELECT this_0_.Id from **FirstQueryOver** 
                                          or **SecondQueryOver** 
                                          or **ThirdQueryOver**))

然后看看你有什么表现。