我正在使用ASP.net Identity 2.0,用户ID为整数。根据我拥有的数据量,执行密码更新是一项非常昂贵的数据库操作,其中2个(不需要的)查询平均128,407个db时间单位,或查询计划中大约7个。
我正在调用的代码(异步或同步是相同的)
var result = await UserManager.ChangePasswordAsync(userId, oldPassword, newPassword);
// or
var result = UserManager.ChangePassword(userId, oldPassword, newPassword);
在数据库中,这会导致两个大的sql调用,这些调用包含在它们的内容中
AspNetUserRoles ... WHERE ((UPPER([Extent1].[Email])) = (UPPER(@p__linq__0))) ...
query 2:
AspNetUserRoles ... WHERE ((UPPER([Extent1].[UserName])) = (UPPER(@p__linq__0))) ...
从我的角度来看
在高层次上,我的问题是 - 是否有解决此问题的方法,或者身份团队中的某个人可以修复代码(如果它确实已损坏)。
更新 对于以下调用(可能还有许多其他调用),可以观察到相同的行为
答案 0 :(得分:2)
嗯,你当然可以自己做,而不是调用那种方法。
想象一下,你在范围内有一个UserManager< ApplicationUser>调用userManager和一个名为context的DbContext。
var user = await context.Users.Single(u => u.Id == knownId);
// You can skip this if you don't care about checking the old password...
if (userManager.PasswordHasher.VerifyHashedPassword(user.HashedPassword, "myOldPassword") == PasswordVerificationResult.Failed) { return; };
user.HashedPassword = userManager.PasswordHasher.HashPassword("myNewPassword");
await context.SaveChangesAsync();
如果仍然没有为您提供足够的优化,DbContext会公开一个Sql方法,因此您只需使用密码hasher来获取哈希值,然后发出一个Update()查询。
我不会做其中任何一件事,除非这确实是一个瓶颈,或者你还有其他一些好的理由。我在我的应用程序中做了类似的事情,因为至少在ASP.NET Identity v1中,没有方法只更改密码而不检查旧密码。
答案 1 :(得分:0)
我相信@emodendroket提供的答案正确有效地回答了我原来的问题。由于需要在短期内修改API的许多部分的含义,我将采用更简单(但不是很好的解决方案)
在电子邮件和用户名上添加计算和持久索引
ALTER TABLE dbo.aspnetusers ADD UpperFieldEmail AS UPPER(email) PERSISTED
CREATE NONCLUSTERED INDEX IX_aspnetusers_UpperFieldEmail ON dbo.aspnetusers(UpperFieldEmail)
ALTER TABLE dbo.aspnetusers ADD UpperFieldUsername AS UPPER(username) PERSISTED
CREATE NONCLUSTERED INDEX IX_aspnetusers_UpperFieldUsername ON dbo.aspnetusers(UpperFieldUsername)