我的处境很奇怪 - 我被要求优化依赖于延迟加载的搜索功能。我意识到速度的主要问题是由于分页请求之间的等待时间(大约 1.5 秒),并且在代码中,我意识到控制器处理的每个页面请求都会导致模型执行完整的数据库查询(而不是仅针对该页面的结果的部分查询)。
我们使用的是自定义 ORM,所以我不确定它在分页方面处理什么(我认为这就是它以这种方式实现的原因)。我们将数据库结果存储到 IEnumerable,然后使用 LINQ 进行过滤以检索正确的页面结果。
我想做的是将这个请求缓存在内存中 - 因为我们将完整的结果放入 IEnumerable 中,所以将其保留在某个地方会很方便(即使我必须将其传递到我的模型中) .
有人建议在我的控制器或模型中使用静态变量,但我认为这会因多个请求而失败。我认为可能有一种方法可以将其临时存储在服务器端会话变量中,并在所有页面请求完成后将其删除。如果愿意的话,可以手动缓存。
我知道这不是最好的方法,但它可能是我在优化方面唯一明智的选择(除非我们转向不同的 ORM)。有人有任何建议、想法或批评吗?我将如何实现这样的事情?
谢谢你。
控制器代码:
[HttpGet, JsonErrorCatcher, NoCache]
public ActionResult Accounts(int page = 0)
{
using (var context = PersistenceContext.Create())
{
var model = new ContactsModel(context);
return new JsonNetResult(model.GetAccountsWebView(CurrentUser, page));
}
}
模型方法:
public ContactsWebViewModel GetAccountsWebView(User user, int page)
{
// This is what I'd like to avoid doing every time, by persisting this value.
// I can pass it into this method if necessary.
IEnumerable<Account> accounts = Context.Get<Account>()
.Include(x => x.AssignedGroups)
.Include(x => x.AssignedUsers)
.Include(x => x.Contacts)
.Where(x => x.IsActive)
.OrderBy(x => x.Name)
.ToArray();
if (!user.HasPermission("Administrator.Contacts:View")) accounts = accounts.Where(x => x.IsReadableBy(user));
int totalPages = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(accounts.Count()) / 25.0));
accounts = accounts.Skip(page * 25).Take(25);
var model = GetWebView(user, null, accounts, page == 0);
model.TotalPages = totalPages;
return model;
}
最简单的解决方案可能是使用内置的 asp.net 缓存。 您没有说明您正在使用哪个版本的框架,但类似的东西应该可以工作。
if (HttpContext.Cache["Key1"] == null)
HttpContext.Cache.Add("Key1", "Value 1", null, DateTime.Now.AddSeconds(60),
Cache.NoSlidingExpiration, CacheItemPriority.High, null);
您可以根据需要调整缓存时间。但请注意,如果结果很大,并且您有多个用户,则很容易耗尽内存或导致巨大的分页延迟..
您可以将搜索条件作为关键,只要使用相同的搜索条件始终返回相同的结果即可。
如果您希望缓存的数据是只读的并且对所有用户都相同,则使用
static
变量不是问题。
如果不是这种情况,那么您应该将 IEnumerable 作为
CacheItem
缓存在 System.Runtime.Caching.MemoryCache
对象中。您可以缓存多个版本以适应可能需要的各种场景。
MSDN 上有关 MemoryCache 的更多信息。