none
Como posso melhorar esta consulta? C# .NET MVC 4 RRS feed

  • 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 DESC

    Com 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 DESC

    ATUALIZAÇÃ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
    terça-feira, 13 de dezembro de 2016 18:37

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
    terça-feira, 13 de dezembro de 2016 19:27

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.

    terça-feira, 13 de dezembro de 2016 18:44
  • Olá Rodrigo.

    Acho uma ideia bem válida. Como poderia fazer essas duas consultas e depois inseri-las em um único retorno para a VIEW, tem alguma sugestão?

    Obrigado

    terça-feira, 13 de dezembro de 2016 19:09
  • 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
    terça-feira, 13 de dezembro de 2016 19:27
  • 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?)

    quarta-feira, 14 de dezembro de 2016 10:41