【问题标题】:Why does Linq To Entities create query that is not optimized为什么 Linq To Entities 创建未优化的查询
【发布时间】:2019-06-29 14:49:14
【问题描述】:

EF 创建了一个使用索引扫描而不是索引搜索的查询。通过稍微修改查询以不使用参数,而是使用索引查找。索引扫描大约需要 3 秒,而 Seek 是即时的。

生成的查询(使用索引扫描):

exec sp_executesql N'SELECT TOP (1) 
    [Extent1].[phone_id] AS [phone_id], 
    [Extent1].[phone] AS [phone], 
    [Extent1].[high_usage_flag] AS [high_usage_flag], 
    [Extent1].[cds_flag] AS [cds_flag], 
    [Extent1].[never_call_flag] AS [never_call_flag], 
    [Extent1].[pa_state_dnc_flag] AS [pa_state_dnc_flag], 
    [Extent1].[ma_state_dnc_flag] AS [ma_state_dnc_flag], 
    [Extent1].[national_dnc_flag] AS [national_dnc_flag], 
    [Extent1].[note] AS [note], 
    [Extent1].[pec_never_call_flag] AS [pec_never_call_flag], 
    [Extent1].[nicor_dnc_flag] AS [nicor_dnc_flag], 
    [Extent1].[css_vici_flag] AS [css_vici_flag], 
    [Extent1].[css_pec_flag] AS [css_pec_flag], 
    [Extent1].[css_vici_alt_flag] AS [css_vici_alt_flag], 
    [Extent1].[area_code] AS [area_code], 
    [Extent1].[phone_type_id] AS [phone_type_id], 
    [Extent1].[last_answer_date] AS [last_answer_date], 
    [Extent1].[csr_bad_flag] AS [csr_bad_flag], 
    [Extent1].[to_process_flag] AS [to_process_flag], 
    [Extent1].[deleted_date] AS [deleted_date], 
    [Extent1].[wireless_flag] AS [wireless_flag]
    FROM [dbo].[phone] AS [Extent1]
    WHERE [Extent1].[phone] = @p__linq__0',N'@p__linq__0 nvarchar(4000)',@p__linq__0=N'555555555'

修改为不使用参数(使用索引查找):

exec sp_executesql N'SELECT TOP (1) 
    [Extent1].[phone_id] AS [phone_id], 
    [Extent1].[phone] AS [phone], 
    [Extent1].[high_usage_flag] AS [high_usage_flag], 
    [Extent1].[cds_flag] AS [cds_flag], 
    [Extent1].[never_call_flag] AS [never_call_flag], 
    [Extent1].[pa_state_dnc_flag] AS [pa_state_dnc_flag], 
    [Extent1].[ma_state_dnc_flag] AS [ma_state_dnc_flag], 
    [Extent1].[national_dnc_flag] AS [national_dnc_flag], 
    [Extent1].[note] AS [note], 
    [Extent1].[pec_never_call_flag] AS [pec_never_call_flag], 
    [Extent1].[nicor_dnc_flag] AS [nicor_dnc_flag], 
    [Extent1].[css_vici_flag] AS [css_vici_flag], 
    [Extent1].[css_pec_flag] AS [css_pec_flag], 
    [Extent1].[css_vici_alt_flag] AS [css_vici_alt_flag], 
    [Extent1].[area_code] AS [area_code], 
    [Extent1].[phone_type_id] AS [phone_type_id], 
    [Extent1].[last_answer_date] AS [last_answer_date], 
    [Extent1].[csr_bad_flag] AS [csr_bad_flag], 
    [Extent1].[to_process_flag] AS [to_process_flag], 
    [Extent1].[deleted_date] AS [deleted_date], 
    [Extent1].[wireless_flag] AS [wireless_flag]
    FROM [dbo].[phone] AS [Extent1]
    WHERE [Extent1].[phone] = ''5555555555'''

谁能告诉我这里发生了什么以及如何让 Linq 使用索引?

【问题讨论】:

  • LINQ 对于除了简单查询之外的任何事情都非常糟糕。我已经看到 LINQ 将 4 个带有 where 条件的表连接翻译成可怕的、执行时间很长的 TSQL 代码。您可以尝试在 SQL Server 中将查询创建为视图或过程,并让代码调用查询或过程。
  • phone.phone的数据类型是什么?
  • @DavidBrowne-Microsoft,您走在正确的轨道上。原来数据类型是varchar,而不是nvarchar,所以没有使用索引

标签: sql-server entity-framework entity-framework-core


【解决方案1】:

问题不是参数嗅探,而是data type precedence。参数类型为 NVarchar,列为 Varchar。 NVarchar 具有较高的数据类型优先级,因此该列将转换为参数类型,并且不能使用索引。

如果您已映射参数,EF Core 将适当地键入参数。因此,您可能缺少模型中的类型配置。 EG

modelBuilder.Entity<Phone>().Property(a => a.Phone).HasColumnType("varchar").HasMaxLength(50);

【讨论】:

猜你喜欢
  • 2013-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多