如何优化这个LINQ到EF / Sql查询(多对多关系)?
我正在实现一个权限系统,其中用户处于角色中,然后这个角色有权限,我正在考虑查询它们的最快方法:
目前我有以下LINQ查询:
var grant = db.Permissions.Any(p => p.Group == group && p.PermissionKey == permission && !p.Roles.Any(r => !r.IsAllowed && r.Role.Users.Any(u => u.UserName == user.Identity.Name)) && p.Roles.Any(r => r.IsAllowed && r.Role.Users.Any(u => u.UserName == user.Identity.Name))); return grant;
EF将实体缓存(第一次15-20ms)后大约需要1-2ms。 这不是很慢,但因为可以查询很多(例如,如果允许用户查看该项目,菜单系统会检查每个项目) 我问的是否有更快的可能性?
我现在唯一能想到的就是创建一个User Permission缓存来在第一次调用之后完全摆脱查询,但缓存对我来说总是最后的选择(特别是当你想到的时候)如果权限更改aso,则清除它。)。
更新:按照Marcin的建议使用Any
,但速度不快……
更新2:我将IsAllowed
移动到映射表并调整查询以仅使用一个…
您应该将每个Count() > 0
语句更改为Any
方法调用,例如:
r => r.Users .Count(u => u.UserName == user.Identity.Name) > 0
应替换为:
r => r.Users .Any(u => u.UserName == user.Identity.Name)
您是否尝试过在数据库中创建索引视图?
CREATE VIEW mySchema.UserRolePermission WITH SCHEMABINDING /* your SELECT goes here */ GO CREATE UNIQUE CLUSTERED INDEX MyIndexName ON mySchema.UserRolePermission (UserName, PermissionKey); GO
然后,您的LINQ2SQL查询将从此视图中直接选择。 它可能更快,因为SQL服务器将在您用于搜索的UserName和PermissionKey字段上创建索引。 由于这是一个权限系统,我假设您不会经常插入这些表(索引视图可能会减慢插入速度)但是您正在更频繁地阅读它。
由于EF缓存,第二次关闭此查询也可能不会更快,但可能是因为SQL服务器缓存。 不确定,但可能值得一试。