ASP.NET MVC5 Identity/OWIN频繁调用INFORMATION_SCHEMA.COLUMNS性能问题
根因分析
- 模型缓存失效:Asp.Net Identity 依赖的IdentityDbContext默认会在首次初始化时构建实体映射模型,但如果OnModelCreating方法未正确调用父类实现,或是存在动态修改模型配置的逻辑,会导致EF的全局模型缓存失效,每次上下文实例化时都会主动查询AspNetUsers表的元数据来重构模型。
- 上下文生命周期配置错误:你当前用NInject注入的IdentityDbContext如果是瞬态生命周期,单次请求中多次调用Repository/Identity服务时会重复实例化上下文,每次实例化都会触发元数据查询,叠加后就会出现每秒数十次的重复查询。
- Identity版本兼容问题:Asp.Net Identity 2.2以前的版本在搭配EF6 Database First模式使用时存在已知bug,不会复用EF的模型缓存,每次操作用户相关数据前都会主动查询AspNetUsers表的结构。
修复方案
1 调整依赖注入生命周期(优先操作,改动最小收益最高)
将Identity相关服务和DbContext的生命周期统一调整为请求内单例,避免单次请求内重复实例化上下文:
// NInject绑定配置示例 kernel.Bind<你的自定义DbContext类名>().ToSelf().InRequestScope(); kernel.Bind<IUserStore<ApplicationUser>>().To<UserStore<ApplicationUser>>().InRequestScope(); kernel.Bind<UserManager<ApplicationUser>>().ToSelf().InRequestScope(); kernel.Bind<SignInManager<ApplicationUser, string>>().ToSelf().InRequestScope();
调整后单次请求只会初始化一次上下文,最多触发一次元数据查询。
2 显式配置Identity实体映射
在DbContext的OnModelCreating方法中显式声明Identity表的映射规则,告诉EF不需要动态查询表结构:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { // 必须优先调用父类方法加载Identity默认配置 base.OnModelCreating(modelBuilder); // 显式指定Identity相关表的映射 modelBuilder.Entity<ApplicationUser>().ToTable("AspNetUsers"); modelBuilder.Entity<IdentityRole>().ToTable("AspNetRoles"); modelBuilder.Entity<IdentityUserRole>().ToTable("AspNetUserRoles"); modelBuilder.Entity<IdentityUserClaim>().ToTable("AspNetUserClaims"); modelBuilder.Entity<IdentityUserLogin>().ToTable("AspNetUserLogins"); // 你的其他业务实体映射配置 }
完成配置后EF会直接复用预定义的映射规则,不会再查询INFORMATION_SCHEMA获取列信息。
3 升级Identity版本
如果当前使用的AspNet Identity版本低于2.2.1,直接升级到2.2.1正式版,该版本已修复Database First模式下重复查询表元数据的问题。
4 数据库侧临时优化
如果暂时无法修改应用代码,可以先在SQL Server创建覆盖索引降低该查询的开销:
CREATE NONCLUSTERED INDEX IX_INFORMATION_SCHEMA_COLUMNS_TableName ON INFORMATION_SCHEMA.COLUMNS (TABLE_NAME) INCLUDE (COLUMN_NAME);
内容的提问来源于stack exchange,提问作者DanDBA
相关产品推荐
相关产品推荐

