我为公司制作的应用程序存在问题。我们正在从ERP系统中查询。人们可以搜索文章,然后应用程序向他们显示所有相关的技术数据,图片和/或数据表。
问题是:加载速度非常慢。查询似乎运行良好,但是视图的生成需要很长时间。
这是我的搜索代码(不用管荷兰语部分):
public IQueryable<Item> GetItems(string vZoekString)
{
db.Configuration.LazyLoadingEnabled = false;
//Split de ZoekString
var searchTerms = vZoekString.ToLower().Split(null);
// TODO: alles in een db query
//Resultaten oplijsten
var term = searchTerms[0];
var results = db.item_general.Where(c => c.ITEM.Contains(term) || c.DSCA.Contains(term));
//Zoeken op alle zoektermen
if (searchTerms.Length > 1)
{
for (int i = 0; i < searchTerms.Length; i++)
{
var tempTerm = searchTerms[i];
results = results.Where(c => c.ITEM.Contains(tempTerm) || c.DSCA.Contains(tempTerm));
}
}
//Show
return results;
然后,将这些结果返回到如下视图:
public ActionResult SearchResults(string vZoekString, string filterValue, int? pageNo)
{
//Bewaking zoekstring
if (vZoekString != null)
{
pageNo = 1;
}
else
{
vZoekString = filterValue;
}
//De zoekstring doorgeven
if (vZoekString == null)
{
return RedirectToAction("Index", "Home");
}
else
{
ViewBag.ZoekString = vZoekString;
}
//Ophalen Items via Business-Object
//var vItems = new SearchItems().GetItems(vZoekString);
SearchItems vSearchItems = new SearchItems();
IQueryable<Item> vItems = vSearchItems.GetItems(vZoekString);
//Nummering
int pageSize = 10;
int page = (pageNo ?? 1);
//Show
return View(vItems.OrderBy(x => x.ITEM).AsNoTracking().ToPagedList(page, pageSize));
}
在我的情况下可能出什么毛病?我在俯视什么吗?
更新:
我已经检查了我的代码,看来一切工作都非常快,但是到达.ToPagedList()
却需要10秒钟以上。所以我的猜测是这有问题。我正在使用Nuget的分页列表。
答案 0 :(得分:1)
虽然我无法不评估您的视图代码,但问题很可能出在数据库查询中。 在使用结果之前,IQueryable实际上不会从数据库中加载任何内容。因此,只有在View代码启动后才能运行数据库查询。
尝试将“查看”调用更改为:
var items = vItems.OrderBy(x => x.ITEM).AsNoTracking().ToPagedList(page, pageSize);
return View(items);
然后检查视图是否仍然是瓶颈。
(这可能应该是评论,但我没有声誉。...)
答案 1 :(得分:0)
在大多数情况下,您会遇到MVC和EF的性能问题,这是由于将实体返回到视图并由于延迟加载而变得st脚。原因是当ASP.Net被告知将对象发送到浏览器时,需要对其进行序列化。序列化过程会在涉及延迟加载代理的实体上进行迭代,从而触发这些相关实体一次加载一个。
您可以通过在数据库上运行探查器,在操作结束之前设置断点,然后观察操作调用返回时执行的查询来检测此问题。由于序列化导致的延迟加载将显示为在页面呈现之前完成操作后迅速连续执行的多个(TOP 1)查询。
避免这种痛苦的最简单建议是不要从控制器返回实体。
IQueryable<Item> vItems = vSearchItems.GetItems(vZoekString);
var viewModels = vItems.OrderBy(x => x.ITEM)
.Select(x => new ItemViewModel
{
ItemId = x.ItemId,
// .. Continue populating view model. If model contains a hierarchy of data, map those to related view models as well.
}).ToPagedList(page, pageSize);
return View(viewModels);
这种方法的好处:
.Select()
将导致查询仅检索填充视图模型所需的数据。 (您的视图所需的数据)查询速度更快,数据库服务器->应用程序服务器->浏览器之间的连线数据更少此方法的警告:
.Select()
表达式将使用SQL,因此没有.Net或私有函数可用于诸如转换/格式化数据之类的工作。将原始值填充到视图模型中,然后在视图模型上公开属性以进行转换,该转换会将已格式化的数据序列化到客户端。像FullName = x.FirstName + " " + x.LastName
这样的基本东西就可以了,但是如果数据库将日期存储为字符串,则应避免像OrderDate = DateTime.Parse(x.DateAsISO)
这样的东西。您可以利用Automapper之类的映射器来协助Entity和ViewModel之间的映射。如果映射工具检查/遍历要填充的目标而不是源,那么您应该很好。 Automapper确实支持IQueryable
内的集成,因此,如果您想利用映射器,这将是一项值得投资的研究。