登录/全表扫描的低效 SQL (UserStore.FindByNameAsync)
Posted
技术标签:
【中文标题】登录/全表扫描的低效 SQL (UserStore.FindByNameAsync)【英文标题】:Inefficient SQL on Login/Full table scan (UserStore.FindByNameAsync) 【发布时间】:2016-01-24 11:48:21 【问题描述】:我们在 Oracle 数据库上使用 Asp.Net Identity 版本 2.2.1 和 EF 6.1.3。
我们确实在 UPPER(USERNAME) 上的用户表上有一个索引,但对于每个用户登录,我们仍然会在我们的用户表上进行全表扫描。
这个问题似乎是由 UserStore 中的这段代码引起的:
public virtual Task<TUser> FindByNameAsync(string userName)
this.ThrowIfDisposed();
return this.GetUserAggregateAsync((
Expression<Func<TUser, bool>>) (u =>
u.UserName.ToUpper() == userName.ToUpper()));
这会导致带有
的 SQLWHERE (((UPPER("Extent1".USERNAME)) = :p__linq__0)
OR ((UPPER("Extent1".USERNAME) IS NULL) AND
(:p__linq__0 IS NULL)))
这个 OR 部分似乎让优化器选择了全表扫描。
使用 SQL Server 时,可以通过将 where 语句更改为:
public virtual Task<TUser> FindByNameAsync(string userName)
this.ThrowIfDisposed();
var uName = userName.ToUpper();
return this.GetUserAggregateAsync((
Expression<Func<TUser, bool>>) (u =>
u.UserName.ToUpper() == uName));
现在是 where 部分:
WHERE N'<USERNAME>' = (UPPER([Extent1].[USERNAME]))
但是我不知道在使用 Oracle 时如何优化它。我已经尝试过 Oracle.Managed 驱动程序和 Devart.Oracle 驱动程序,当在字段上使用 UPPER 函数时,它们都使用 OR 生成 where 语句。
数据库中必须有不区分大小写的用户名。
那么,当我们使用 UPPER(field) = something 时,为什么 EF 会生成带有 OR 语句的 SQL 呢?
还有其他方法可以解决这个问题吗?有没有人有好的解决方案?
此时,我们的最后一个选项可能是在数据表中将用户名设为大写,从而避免使用大写函数——但这似乎不是最佳解决方案。
【问题讨论】:
你试过了吗-看我的回答尝试 No..upper
正在强制进行表扫描。在列周围放置一个函数使其不可分割(查找)
@Nick.McDermaid,查找基于函数的索引。如果 OP 在 'upper(...)' 上有一个索引,如 OP 所述,那么它是 sargable。
是的 - 我没有注意到那部分。
ErikEJ 在现场。此设置使 EF 按我的意愿创建 SQL。谢谢!
【参考方案1】:
你试过设置吗
context.UseDatabaseNullSemantics = true;
https://msdn.microsoft.com/en-us/library/system.data.entity.infrastructure.dbcontextconfiguration.usedatabasenullsemantics(v=vs.113).aspx
【讨论】:
以上是关于登录/全表扫描的低效 SQL (UserStore.FindByNameAsync)的主要内容,如果未能解决你的问题,请参考以下文章