在MVC Razor中从数据库获取数据时LINQ查询性能问题
问题陈述: 我正在尝试使用Linq查询将数据库中的多表数据绑定到视图,这需要更多的时间。我在数据库中有大约10000条记录。有人建议使用IQueryable而不是IEnumerable,但它是否会影响我当前的代码(在视图和控制器中)??或者不使用它,我能做到这一点吗 我应该怎么做才能提高加载结果的性能?? 我做错了什么?? 请给我建议一些更好的方法…… 控制器:在MVC Razor中从数据库获取数据时LINQ查询性能问题,linq,asp.net-mvc-4,razor,linq-to-sql,Linq,Asp.net Mvc 4,Razor,Linq To Sql,问题陈述: 我正在尝试使用Linq查询将数据库中的多表数据绑定到视图,这需要更多的时间。我在数据库中有大约10000条记录。有人建议使用IQueryable而不是IEnumerable,但它是否会影响我当前的代码(在视图和控制器中)??或者不使用它,我能做到这一点吗 我应该怎么做才能提高加载结果的性能?? 我做错了什么?? 请给我建议一些更好的方法…… 控制器: public ActionResult Index() { var result = (from pr in
public ActionResult Index()
{
var result = (from pr in db.Prod.AsEnumerable()
join s in db.Shift.AsEnumerable() on pr.Shift equals s.ShiftID
join m in db.Module.AsEnumerable() on pr.Module equals m.ModuleID
select new GlobalModel()
{
prodModelIndex = pr,
prodModel = prodModel,
shiftModel = s,
moduleModel = m,
ddlShift = objTransactionGeneralController.GetAllShift(),
ddlModule = objTransactionGeneralController.GetAllModule()
}).ToList();
return PartialView(result);
}
public TransGeneralModel GetAllModule()
{
objTransGeneralModel.ddlModule = (from m in db.Module.AsEnumerable()
select new SelectListItem
{
Value = m.ModuleID.ToString(),
Text = m.ModuleName,
}).ToList();
return objTransGeneralModel;
}
public TransGeneralModel GetAllShift()
{
objTransGeneralModel.ddlShift = (from s in db.Shift.AsEnumerable()
select new SelectListItem
{
Value = s.ShiftID.ToString(),
Text = s.ShiftName,
}).ToList();
return objTranGeneralModel;
}
@model IEnumerable<SIA.Models.Trans.GlobalModel>
@using GridMvc.Html
@{
Layout = "~/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Index";
}
<link rel="stylesheet" href="@Url.Content("~/Content/jquery.dataTables.min.css")">
<script src="@Url.Content("~/Scripts/jquery-2.1.1.min.js")"></script>
<h2>Details</h2>
<hr />
<div style="width: 1000px; padding-left: 70px">
@Html.Partial("Create")
<br />
</div>
<h5 class="pull-right">
<b class="fa fa-keyboard-o" style="color: blue"></b>
@Ajax.ActionLink("Edit", "ProdEdit", "Prod", new { }, new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "prod-details",
HttpMethod = "GET",
}, new { style = "color:blue" })
</h5>
<br />
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
if (Model.FirstOrDefault().prodModelIndex != null)
{
<div id="prod-details">
<table class="table table-striped" id="tblProdDetails">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().prodModelIndex.ProdID)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().prodModelIndex.Date)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().prodModelIndex.Module)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().productionModelIndex.Shift)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().prodModelIndex.Hour)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().prodModelIndex.Output)
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr id="customer-row-@item.prodModelIndex.ProdID">
<td>
@Html.DisplayFor(modelItem => item.prodModelIndex.ProdID)
</td>
<td>
@Html.DisplayFor(modelItem => item.prodModelIndex.Date)
</td>
<td>
@Html.DisplayFor(modelItem => item.moduleModel.ModuleName)
</td>
<td>
@Html.DisplayFor(modelItem => item.shiftModel.ShiftName)
@Html.HiddenFor(modelItem => item.prodModelIndex.Shift)
</td>
<td>
@Html.DisplayFor(modelItem => item.prodModelIndex.Hour)
</td>
<td>
@Html.DisplayFor(modelItem => item.prodModelIndex.Output)
</td>
</tr>
}
</tbody>
</table>
</div>
}
}
<script>
$(document).ready(function () {
$('#tblProdDetails').dataTable({
"order": [[1, "desc"], [3, "asc"]]
});
});
</script>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
@Scripts.Render("~/Scripts/jquery.dataTables.min.js")
<script type='text/javascript'>
$(function () {
$('.datepicker').datepicker({
format: "dd M yyyy",
}).on('changeDate', function (e) {
$(this).datepicker('hide');
});
})
</script>
}
查看:
public ActionResult Index()
{
var result = (from pr in db.Prod.AsEnumerable()
join s in db.Shift.AsEnumerable() on pr.Shift equals s.ShiftID
join m in db.Module.AsEnumerable() on pr.Module equals m.ModuleID
select new GlobalModel()
{
prodModelIndex = pr,
prodModel = prodModel,
shiftModel = s,
moduleModel = m,
ddlShift = objTransactionGeneralController.GetAllShift(),
ddlModule = objTransactionGeneralController.GetAllModule()
}).ToList();
return PartialView(result);
}
public TransGeneralModel GetAllModule()
{
objTransGeneralModel.ddlModule = (from m in db.Module.AsEnumerable()
select new SelectListItem
{
Value = m.ModuleID.ToString(),
Text = m.ModuleName,
}).ToList();
return objTransGeneralModel;
}
public TransGeneralModel GetAllShift()
{
objTransGeneralModel.ddlShift = (from s in db.Shift.AsEnumerable()
select new SelectListItem
{
Value = s.ShiftID.ToString(),
Text = s.ShiftName,
}).ToList();
return objTranGeneralModel;
}
@model IEnumerable<SIA.Models.Trans.GlobalModel>
@using GridMvc.Html
@{
Layout = "~/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Index";
}
<link rel="stylesheet" href="@Url.Content("~/Content/jquery.dataTables.min.css")">
<script src="@Url.Content("~/Scripts/jquery-2.1.1.min.js")"></script>
<h2>Details</h2>
<hr />
<div style="width: 1000px; padding-left: 70px">
@Html.Partial("Create")
<br />
</div>
<h5 class="pull-right">
<b class="fa fa-keyboard-o" style="color: blue"></b>
@Ajax.ActionLink("Edit", "ProdEdit", "Prod", new { }, new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "prod-details",
HttpMethod = "GET",
}, new { style = "color:blue" })
</h5>
<br />
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
if (Model.FirstOrDefault().prodModelIndex != null)
{
<div id="prod-details">
<table class="table table-striped" id="tblProdDetails">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().prodModelIndex.ProdID)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().prodModelIndex.Date)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().prodModelIndex.Module)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().productionModelIndex.Shift)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().prodModelIndex.Hour)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().prodModelIndex.Output)
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr id="customer-row-@item.prodModelIndex.ProdID">
<td>
@Html.DisplayFor(modelItem => item.prodModelIndex.ProdID)
</td>
<td>
@Html.DisplayFor(modelItem => item.prodModelIndex.Date)
</td>
<td>
@Html.DisplayFor(modelItem => item.moduleModel.ModuleName)
</td>
<td>
@Html.DisplayFor(modelItem => item.shiftModel.ShiftName)
@Html.HiddenFor(modelItem => item.prodModelIndex.Shift)
</td>
<td>
@Html.DisplayFor(modelItem => item.prodModelIndex.Hour)
</td>
<td>
@Html.DisplayFor(modelItem => item.prodModelIndex.Output)
</td>
</tr>
}
</tbody>
</table>
</div>
}
}
<script>
$(document).ready(function () {
$('#tblProdDetails').dataTable({
"order": [[1, "desc"], [3, "asc"]]
});
});
</script>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
@Scripts.Render("~/Scripts/jquery.dataTables.min.js")
<script type='text/javascript'>
$(function () {
$('.datepicker').datepicker({
format: "dd M yyyy",
}).on('changeDate', function (e) {
$(this).datepicker('hide');
});
})
</script>
}
@model IEnumerable
@使用GridMvc.Html
@{
Layout=“~/Views/Shared/_Layout.cshtml”;
ViewBag.Title=“Index”;
}
细节
@Html.Partial(“创建”)
@ActionLink(“Edit”、“ProdEdit”、“Prod”、new{}、new AjaxOptions
{
InsertionMode=InsertionMode.Replace,
UpdateTargetId=“产品详细信息”,
HttpMethod=“GET”,
},新{style=“color:blue”})
@使用(Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
if(Model.FirstOrDefault().prodModelIndex!=null)
{
@DisplayNameFor(model=>model.FirstOrDefault().prodModelIndex.ProdID)
@DisplayNameFor(model=>model.FirstOrDefault().prodModelIndex.Date)
@DisplayNameFor(model=>model.FirstOrDefault().prodModelIndex.Module)
@DisplayNameFor(model=>model.FirstOrDefault().productionModelIndex.Shift)
@DisplayNameFor(model=>model.FirstOrDefault().prodModelIndex.Hour)
@DisplayNameFor(model=>model.FirstOrDefault().prodModelIndex.Output)
@foreach(模型中的var项目)
{
@DisplayFor(modelItem=>item.prodModelIndex.ProdID)
@DisplayFor(modelItem=>item.prodModelIndex.Date)
@DisplayFor(modelItem=>item.moduleModel.ModuleName)
@DisplayFor(modelItem=>item.shiftModel.ShiftName)
@HiddenFor(modeleItem=>item.prodModelIndex.Shift)
@DisplayFor(modelItem=>item.prodModelIndex.Hour)
@DisplayFor(modelItem=>item.prodModelIndex.Output)
}
}
}
$(文档).ready(函数(){
$('#tblProdDetails')。数据表({
“订单”:[[1,“说明”],[3,“asc”]]
});
});
@节脚本{
@Scripts.Render(“~/bundles/jqueryval”)
@Scripts.Render(“~/Scripts/jquery.dataTables.min.js”)
$(函数(){
$('.datepicker').datepicker({
格式:“dd M yyy”,
}).on('changeDate',函数(e){
$(this.datepicker('hide');
});
})
}
首先,当您调用像ToList()
、AsEnumerable()
或FirstOrDefault()
这样的方法时,它将在数据库上执行查询。在您的情况下,最好删除它们,以使用连接来点击单个查询
var result = (from pr in db.Prod
join s in db.Shift on pr.Shift equals s.ShiftID
join m in db.Module on pr.Module equals m.ModuleID
select new GlobalModel()
{
prodModelIndex = pr,
prodModel = prodModel,
shiftModel = s,
moduleModel = m
}).ToList();
如果表由外键引用,则无需联接。您可以像这样直接访问引用的记录
var result = (from pr in db.Prod
select new GlobalModel()
{
prodModelIndex = pr,
prodModel = prodModel,
shiftModel = pr.Shift,
moduleModel = pr.Module
}).ToList();
TL;DR
- 使用
.Where
筛选主表(Prod),或者至少使用.Take()
将行数限制为屏幕上显示的正常行数
- 删除
.AsEnumerable()
-您正在将整个表具体化到内存中
- 向表中添加外键,重新生成DBML,并使用导航而不是显式联接
- 请注意在
Select
projection中输入的内容-ddlShift=objTransactionGeneralController。结果集中的每一行都将调用GetAllShift()
详细信息
通过将.AsEnumerable()
应用于您的集合,如:
var result = (from pr in db.Prods.AsEnumerable()
join s in db.Shifts.AsEnumerable() on pr.ShiftID equals s.ShiftId
join m in db.Modules.AsEnumerable() on pr.ModuleID equals m.ModuleId
select new ...
您当前的代码会导致对Sql Server的3个显式查询,每个查询都会将整个表加载到内存中:(例如,使用Sql Profiler
,或LinqPad
,等等)
考虑到您根本没有WHERE
谓词,这可能不会比加入数据库慢多少。然而,一般来说,这样做根本不是一个好主意,因为:
通过应用.AsEnumerable()
,您将剥夺Linq2Sql将IQueryable
表达式树解析为本机Sql的能力。通常,在数据库中进行连接和筛选会比在内存中进行更快,并且需要的内存更少。假设Prod
,Shift
和Module
是Lin
SELECT TOP 1000 [t0].[ProdID], [t0].[ShiftID], [t0].[ModuleID], [t1].[ShiftId] AS [ShiftId2], [t2].[ModuleId] AS [ModuleId2]
FROM [dbo].[Prod] AS [t0]
INNER JOIN [dbo].[Shift] AS [t1] ON [t0].[ShiftID] = ([t1].[ShiftId])
INNER JOIN [dbo].[Module] AS [t2] ON [t0].[ModuleID] = ([t2].[ModuleId])
WHERE [t0].[ProdID] BETWEEN 5 AND 10;