none
Nvarchar(4000) e Index Scan RRS feed

  • Pergunta

  • Pessoal,

    recentemente andei olhando algumas queries ofensoras da aplicação no banco de dados e percebi que essa simples consulta está fazendo um pequeno estrago no meu bd de produção:

    declare @p__linq__0 NVARCHAR(4000)
    
    SELECT TOP (1) [Extent1].[IdUser] AS [IdUser]
    	,[Extent1].[Username] AS [Username]
    FROM [TbUser] AS [Extent1]
    WHERE [Extent1].[Username] = @p__linq__0

    Acontece que o que está fazendo a query ficar ruim é o parâmetro passado, Nvarchar(4000), esse Nvarchar(4000) é atribuído automaticamente á variável @p__linq__0 e faz com que o SQL tenha que fazer uma conversão implícita, o que impacta em um índice SCAN, ao invés de fazer o indice SEEK.

    Na tabela, campo UserName é um varchar(50), se eu passar esse parâmetro com o tipo de dados correto, que é o varchar(50), o SQL não precisa fazer a conversão e usa meu índice corretamente.

    Minha dúvida é: Existe alguma maneira de configurar o EF para que ele mapeie a variável com o tipo de dados e tamanho da coluna? Se eu puder setar manualmente resolver também, bastaria eu alterar o tipo de dados de Nvarchar(4000) para Varchar(50).

    Segue plano de execução com o SCAN:

    segunda-feira, 19 de novembro de 2012 18:24

Todas as Respostas

  • Olá Leonardo,

    Qual versão do EF vc esta utilizando?

    []s!


    Fernando Henrique Inocêncio Borba Ferreira
    Microsoft MVP - Data Platform Development
    while(alive){ this.WriteCode(); }
    Blog: http://ferhenriquef.com/
    Twitter: @ferhenrique
    Entity Framework - Brasil: https://www.facebook.com/EntityFrameworkBrasil

    terça-feira, 20 de novembro de 2012 12:54
    Moderador
  • Fernando,

    estamos utilizando a versão 5.0 e esse probleminha tem me atormentado !

    terça-feira, 20 de novembro de 2012 13:21
  • Você pode setar o tamanho tanto com DataAnotations na propriedade Username, como utilizar Fluent Api para configurar seus relacionamentos. Prefiro o último.

    http://odetocode.com/Blogs/scott/archive/2011/11/24/composing-entity-framework-fluent-configurations.aspx

    quarta-feira, 21 de novembro de 2012 02:12
  • Danimar, tentamos fazer a alteração das duas maneiras, uma pelo Fluent API e outra pelo Data Anotation, conforme código abaixo:

    Fluent API:
    modelBuilder.Entity<Customer>()
                    .HasKey(e => e.IdCustomer)
                    .Map(e => e.ToTable("TbCustomer", "AM"));
    modelBuilder.Entity<Customer>()
                    .Property(c => c.Username)
                    .HasMaxLength(50);
    
    
    Data Anotation:
    
    [StringLength(50)]
    public string Username { get; set; }

    Em ambos os casos, a query continua vindo com o nvarchar(4000), ou seja, nossas alterações não fizeram efeito.

    Poderia dar uma olhada por favor e dizer se o caminho é esse mesmo?

    quarta-feira, 21 de novembro de 2012 17:22
  • Via Data Anotation não tenho certeza se é StringLength.

    Eu usava [MaxLength(2)], mas isso se não me engano depende da versão do EF, parece que foi mudado.

    Quanto ao Fluent API, seria isso mesmo.  No meu caso eu uso uma classe para mapear, mas você pode mapear diretamente.

     protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
                modelBuilder.Configurations.Add(new Condicao_Pagamento_Mapping());

    }

    quarta-feira, 21 de novembro de 2012 17:56
  • É cara, acho que o MaxLenght saiu de circulação mesmo, vou procurar o equivalente a ele no E.F. 5.0 e tentar fazer a mudança, infelizmente pelo Fluent API também não mudou, continuou mandando como Nvarchar(4000).

    Estou desconfiado de alguma configuração que tenha precedência sobre o "maxlenght" e o Fluent API.

    quarta-feira, 21 de novembro de 2012 18:33
  • Para que o EF use a propriedade UserName como VARCHAR em vez de NVARCHAR basta adicionar o atributo na propriedade (Data Anotation):


    [Column(TypeName = "varchar")]

    public string Username { get; set; }

    Ou pelo FluentApi:

    modelBuilder.Entity<TbUser>()
      .Property(e => e.UserName).HasColumnType("VARCHAR").HasMaxLength(50);


    Att,
    Breno Queiroz

    StudioWs3 - Soluções Web

    quinta-feira, 29 de novembro de 2012 20:39