3

I became aware of a performance difference when using parameterized queries generated by EntityFramework when using an Azure SQL database.

I have a table with a varchar(30) primary key and when I try to get a value from that table using the primary key, EntityFramework creates a parameterized query using NVARCHAR(4000) as the datatype.

DECLARE @p__linq__0 nvarchar(4000)
SET @p__linq__0 ='ehenurqp0kpql76kjsw3'

select * from mediacontentreferences where mediacontentreferenceid=@p__linq__0

This generates a very strange execution plan on the Azure SQL database.

Azure SQL execution plan 1

It is quite ineffective since it uses an Index Scan that looks through the whole table.

If I use a parameter with the correct datatype, the execution plan uses the primary key index.

DECLARE @p__linq__1 varchar(30)
SET @p__linq__1 ='ehenurqp0kpql76kjsw3'

select * from mediacontentreferences where mediacontentreferenceid=@p__linq__1

Azure SQL execution plan 2

If I use the first query on an on-premises SQL server, the execution plan converts the NVARCHAR(4000) to a VARCHAR(30) and uses the primary key index. SQL Server execution plan 1

This looks like a flaw in the execution plan calculation on the Azure SQL server.

Is there a possibility to change the behavior of Entity Framework on how it creates the queries?

I have read a couple articles regarding this but no solution where found there.

Why does code first/EF use 'nvarchar(4000)' for strings in the raw SQL command?

Why does Entity Framework generate large parameters? How can they be reduced?

5
  • What version of SQL Server is the on-premises machine? Commented Nov 29, 2017 at 12:37
  • Use the hasmaxlength setting for the column? prashantbrall.wordpress.com/2011/04 Commented Nov 29, 2017 at 12:41
  • on-premises, have tested both 2008 R2 and 2014, both works
    – Dan
    Commented Nov 29, 2017 at 14:01
  • length of the column has no effect, but if I change the parameter type to varchar (same as column) it works on azure regardless of the length
    – Dan
    Commented Nov 29, 2017 at 14:02
  • The reason I ask is because the Azure optimizer is more in line, or slightly ahead of, SQL Server 2017. So comparing 2014, or earlier, behavior with Azure isn't going to be very accurate. Commented Nov 29, 2017 at 18:28

1 Answer 1

2

You must specify right datatype for your column, than EF while generating queries will declare parameters with a right data type. Just add this to your DbContext:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<mediacontentreferences >().Property(e => e.mediacontentreferenceid).HasColumnType("varchar");
    }
7
  • Yes, this will fix the actual query generated by EntityFramework (thx), but it does not answer why the Azure SQL Server uses that "creative" execution plan on the supplied query
    – Dan
    Commented Nov 29, 2017 at 14:20
  • @Dan, This has nothing to do with Azure. Problem is that if you define your column with varchar datatype, but declare parameter with nvarchar in your query, SQL server must do a type conversion and is unable to use your index. Commented Nov 29, 2017 at 14:25
  • But why does the different SQL server versions come up with different plans? It only suggest an Index Scan if your datatypes does not match and you run it on Azure?
    – Dan
    Commented Nov 29, 2017 at 14:39
  • The optimizer is different between 2014 and Azure. 2014 still didn't enable all optimizer updates by default (2016 and greater does). Azure does. I wouldn't be at all surprised to see different behavior. Commented Nov 29, 2017 at 18:29
  • I can confirm that the same behavior occurs for SQL server 2016 so it might have to do with "optimization". Have a hard time to see why it cannot come up with a more clever plan for select * from x where id=N'123' compared to select * from x where id='123'
    – Dan
    Commented Dec 2, 2017 at 7:53

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.