2012-10-03 66 views
6
usuarios

Hola StackOverflow,NHibernate - Unión tres QueryOvers

me encontré con este problema que tienen tres QueryOvers y cada uno de ellos devuelve una lista de identificadores de candidatos que luego utilizo para llevar a los candidatos. Para esto escribí el siguiente código.

 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)))); 
    } 

Esto devuelve los resultados correctos y la consulta generada se parece a esto

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**)) 

El problema es que utiliza 'o'. Debido a esto, la consulta es dolorosamente lenta.

Si en vez escribo esto:

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

Termina casi al instante.

¿Tiene alguna idea de cómo debería refactorizar el código para un mejor rendimiento?

Gracias, Adrian.

+0

está haciendo una opción en memoria de la Unión? –

+0

@ Andrew Whitaker me terminó haciendo justamente eso, pero realmente no me gusta porque hay registros devueltos por más de una consulta así que tengo que eliminar los duplicados de forma manual. –

Respuesta

1

he buscado, pero no encontró nada, así que hice este truco:

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()))); 
} 

No es la mejor solución, pero debería funcionar.

0

no puedo decir por qué el o frente a la unión tiene un diffrence tales. El Analizador de SQL, analizador de consultas y el plan de ejecución estimado deben darle una visión más clara en lo que hace SQL para ejecutar la consulta, supongo que no está utilizando el índice derecho en el primer caso. Sin embargo, trataría de reescribir su consulta a:

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

y ver qué rendimiento tiene entonces.

+0

Hola compañeros, gracias por tu ayuda. Verificaré los índices que tengo en mis columnas. Sin embargo, le agradecería mucho si pudiera darme pistas para refactorizar el código C#. –