【问题标题】:Azure SQL slow performance on parameterized queries NVARCHAR(4000)Azure SQL 在参数化查询 NVARCHAR(4000) 上性能缓慢
【发布时间】:2018-05-12 22:11:44
【问题描述】:

我意识到在使用 Azure SQL 数据库时使用 EntityFramework 生成的参数化查询时的性能差异。

我有一个带有 varchar(30) 主键的表,当我尝试使用主键从该表中获取值时,EntityFramework 使用 NVARCHAR(4000) 作为数据类型创建参数化查询。

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

select * from mediacontentreferences where mediacontentreferenceid=@p__linq__0

这会在 Azure SQL 数据库上生成一个非常奇怪的执行计划。

这是非常无效的,因为它使用了查看整个表的索引扫描。

如果我使用具有正确数据类型的参数,执行计划将使用主键索引。

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

select * from mediacontentreferences where mediacontentreferenceid=@p__linq__1

如果我在本地 SQL 服务器上使用第一个查询,执行计划会将 NVARCHAR(4000) 转换为 VARCHAR(30) 并使用主键索引。

这看起来像是 Azure SQL 服务器上的执行计划计算中的一个缺陷。

是否有可能改变实体框架创建查询的行为?

我已经阅读了几篇关于此的文章,但没有找到解决方案。

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?

【问题讨论】:

  • 本地机器是什么版本的 SQL Server?
  • 对列使用 hasmaxlength 设置? prashantbrall.wordpress.com/2011/04
  • 在本地,已经测试了 2008 R2 和 2014,两者都有效
  • 列的长度没有影响,但如果我将参数类型更改为 varchar(与列相同),无论长度如何,它都适用于 azure
  • 我问的原因是因为 Azure 优化器更符合或稍微领先于 SQL Server 2017。因此,与 2014 年或更早的版本相比,Azure 的行为不会非常准确。

标签: sql-server entity-framework azure-sql-database


【解决方案1】:

您必须为列指定正确的数据类型,而不是 EF 在生成查询时将声明具有正确数据类型的参数。只需将其添加到您的 DbContext:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<mediacontentreferences >().Property(e => e.mediacontentreferenceid).HasColumnType("varchar");
    }

【讨论】:

  • 是的,这将修复 EntityFramework (thx) 生成的实际查询,但它没有回答为什么 Azure SQL Server 在提供的查询上使用该“创造性”执行计划
  • @Dan,这与 Azure 无关。问题是,如果您使用 varchar 数据类型定义列,但在查询中使用 nvarchar 声明参数,SQL Server 必须进行类型转换并且无法使用您的索引。
  • 但是为什么不同的SQL server版本会拿出不同的方案呢?如果您的数据类型不匹配并且您在 Azure 上运行它,它只会建议进行索引扫描?
  • 2014 和 Azure 的优化器不同。默认情况下,2014 仍然没有启用所有优化器更新(2016 和更高版本)。 Azure 可以。看到不同的行为,我一点也不感到惊讶。
  • 我可以确认 SQL Server 2016 也会发生相同的行为,因此它可能与“优化”有关。很难理解为什么它不能为 select * from x where id=N'123' 与 select * from x where id='123' 相比提出一个更聪明的计划
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-11
  • 1970-01-01
  • 2017-12-10
相关资源
最近更新 更多