Usuário com melhor resposta
Como posso melhorar esta consulta? C# .NET MVC 4

Pergunta
-
Olá, tudo certo?
Tenho esta consulta abaixo, porém é muito lenta. Haveria alguma maneira para melhora-la? Se eu usar SQL Connection, escrevendo a query no código, teria algum ganho significativo?
return Session.CreateCriteria<TNotification>()
.CreateAlias("TClientNotifications", "clientNotifications", JoinType.LeftOuterJoin)
.SetFetchMode("clientNotifications.Client", FetchMode.Eager)
.CreateAlias("clientNotifications.Client", "client", JoinType.LeftOuterJoin)
.Add(Restrictions.Or(Restrictions.Eq("IsToAll", true), Restrictions.Eq("client.Id", client.Id)))
.AddOrder(Order.Desc("Id"))
.List<TNotification>()
.DistinctBy(x => x.Id)
.ToList();O propósito dela é exibir notificações para os clientes, assim que acessam uma página específica com seu usuário e senha. Exibe as notificações cadastradas pra ele (cliente) e as notificações que devem ser exibidas para todos os clientes.
Se eu faço esta no banco de dados (uso SQL Server) sem DISTINCT, retornam mais de 11 mil registros
SELECT *
FROM t_notifications n WITH(NOLOCK)
LEFT JOIN t_client_notifications cn WITH(NOLOCK) ON n.id = cn.id_notification
WHERE cn.id_client = 16424 OR n.is_to_all = 1
ORDER BY n.id DESCCom DISTINCT, retorna o número de notificações para o cliente, e está última, acredito eu, é igual a citada acima, e no SQL retorna bem rápido.
SELECT DISTINCT n.id
FROM t_notifications n WITH(NOLOCK)
LEFT JOIN t_client_notifications cn WITH(NOLOCK) ON n.id = cn.id_notification
WHERE cn.id_client = 16424 OR n.is_to_all = 1
ORDER BY n.id DESCATUALIZAÇÃO 14/12/2016 10H
Meu método ficou da seguinte maneira:
public List<TNotification> GetNotifications(TClient client)
{
var notificacoesClient = Session.CreateCriteria<TNotification>()
.CreateAlias("TClientNotifications", "clientNotifications", JoinType.LeftOuterJoin)
.SetFetchMode("clientNotifications.Client", FetchMode.Eager)
.CreateAlias("clientNotifications.Client", "client", JoinType.LeftOuterJoin)
.Add(Restrictions.Eq("client.Id", client.Id))
.AddOrder(Order.Desc("Id"))
.List<TNotification>();
var notificacoesAll = Session.CreateCriteria<TNotification>()
.Add(Restrictions.Eq("IsToAll", true))
.AddOrder(Order.Desc("Id"))
.List<TNotification>();
#region código antigo
//return Session.CreateCriteria<TNotification>()
// .CreateAlias("TClientNotifications", "clientNotifications", JoinType.LeftOuterJoin)
// .SetFetchMode("clientNotifications.Client", FetchMode.Eager)
// .CreateAlias("clientNotifications.Client", "client", JoinType.LeftOuterJoin)
// .Add(Restrictions.Or(Restrictions.Eq("IsToAll", true), Restrictions.Eq("client.Id", client.Id)))
// .AddOrder(Order.Desc("Id"))
// .List<TNotification>()
// .DistinctBy(x => x.Id)
// .ToList();
#endregion
var resultadoFinal = notificacoesAll.Union(notificacoesClient).ToList();
return resultadoFinal;
}- Editado Felipe Negro quarta-feira, 14 de dezembro de 2016 12:00 Finalizado
Respostas
-
Uma opção poderia ser assim:
var geral = Session.CreateCriteria<TNotification>()
.Add(Restrictions.Eq("IsToAll", true))
.AddOrder(Order.Desc("Id"))
.List<TNotification>()
.ToList();
var cliente = Session.CreateCriteria<TNotification>()
.CreateAlias("TClientNotifications", "clientNotifications", JoinType.LeftOuterJoin)
.SetFetchMode("clientNotifications.Client", FetchMode.Eager)
.CreateAlias("clientNotifications.Client", "client", JoinType.LeftOuterJoin)
.Add(Restrictions.Eq("client.Id", client.Id))
.AddOrder(Order.Desc("Id"))
.List<TNotification>()
.ToList();
return geral.Union(cliente);
- Marcado como Resposta Felipe Negro quarta-feira, 14 de dezembro de 2016 12:00
Todas as Respostas
-
Olá Felipe,
O que acha de fazer a query em duas etapas, uma que busca as notificações para o cliente usando inner join e outra que busca as notificações gerais?
A nível de consulta, o uso de OR pode fazer com que o banco não vá pelo índice das colunas, o que deixa o desempenho inferior, neste caso pode ser melhor duas queries.
-
-
Uma opção poderia ser assim:
var geral = Session.CreateCriteria<TNotification>()
.Add(Restrictions.Eq("IsToAll", true))
.AddOrder(Order.Desc("Id"))
.List<TNotification>()
.ToList();
var cliente = Session.CreateCriteria<TNotification>()
.CreateAlias("TClientNotifications", "clientNotifications", JoinType.LeftOuterJoin)
.SetFetchMode("clientNotifications.Client", FetchMode.Eager)
.CreateAlias("clientNotifications.Client", "client", JoinType.LeftOuterJoin)
.Add(Restrictions.Eq("client.Id", client.Id))
.AddOrder(Order.Desc("Id"))
.List<TNotification>()
.ToList();
return geral.Union(cliente);
- Marcado como Resposta Felipe Negro quarta-feira, 14 de dezembro de 2016 12:00
-
Rodrigo, tudo certo?
As duas consultas funcionam perfeitamente, apenas o UNION que gera a seguinte mensagem:
Cannot implicity convert type 'System.Collections.Generic.IEnumerable<boulevard.Domain.TNotification>' to 'System.Collections.Generic.List<boulevard.Domain.TNotification>'. An explicit conversion exists (are you missing a cast?)