提问人: 提问时间:3/16/2022 更新时间:3/16/2022 访问量:531
jQuery DataTable 服务器端处理性能
jQuery DataTable Server Side Processing Performance
问:
我目前的数据表解决方案需要 1.5 - 2 秒来抓取 5k+ 记录并显示它们。
当前操作/方法:
public JsonResult LoadDrawings()
{
return Json(new { data = GetDrawings("") }, JsonRequestBehavior.AllowGet);
}
private IEnumerable GetDrawings(string keyword)
{
var drawings = from d in _db.Drawings
where d.DrawingNumber.ToString().Contains(keyword)
|| d.Drawer.Contains(keyword)
|| d.DrawingDate.ToString().Contains(keyword)
|| d.DrawingCategories.Any(c => c.Label.Contains(keyword))
|| d.Room.Label.Contains(keyword)
|| d.Notes.Contains(keyword)
|| d.Streets.Any(s => s.Street_.Contains(keyword))
|| d.Streets.Any(s => s.StreetCategories.Any(c => c.Label.Contains(keyword)))
|| d.Trs.Any(s => s.TrsSection.Label.Contains(keyword))
|| d.Trs.Any(t => t.TrsTownship.Label.Contains(keyword))
|| d.Trs.Any(r => r.TrsRanx.Label.Contains(keyword))
select new
{
d.DrawingNumber, d.Drawer, d.DrawingDate,
DrawingCategories = d.DrawingCategories.Select(c => c.Label).ToList(),
Room = d.Room.Label, d.Notes, Streets = d.Streets.Select(s => s.Street_).ToList(),
StreetCategories = d.Streets.Select(s => s.StreetCategories.Select(c => c.Label)).ToList(),
TrsSections = d.Trs.Select(s => s.TrsSection.Label).ToList(),
TrsTownships = d.Trs.Select(t => t.TrsTownship.Label).ToList(),
TrsRanges = d.Trs.Select(r => r.TrsRanx.Label).ToList(), d.Id
};
return drawings;
}
当前 DataTable 脚本:
<script>
$(document).ready(function () {
$("#DrawingDataTable").DataTable({
autoWidth: false,
deferRender: true,
order: [0, "desc"],
ajax: {
url: '@Url.Action("LoadDrawings", "Drawing")',
datatype: "json",
type: "GET"
},
columnDefs: [
{
targets: [3, 6, 7, 8, 9, 10],
searchable: true,
visible: false
},
{
targets: 11,
searchable: false,
visible: false
},
{
targets: [12, 13],
orderable: false,
searchable: false,
width: "1%"
},
{
targets: [1, 4, 5],
className: "uppercase"
}
],
columns: [
{
data: "DrawingNumber",
render: function (data, type, row) {
var drawingDetails = '@Url.Action("Details", "Drawing")/' + row.Id;
return '<a href=\"' + drawingDetails + '">' + data + '</a>';
}
},
{ data: "Drawer" },
{
data: "DrawingDate",
render: function (data) {
return moment(data).format("MM/DD/YYYY");
}
},
{ data: "DrawingCategories" },
{ data: "Room" },
{ data: "Notes" },
{ data: "Streets" },
{ data: "StreetCategories" },
{ data: "TrsSections" },
{ data: "TrsTownships" },
{ data: "TrsRanges" },
{ data: "Id" },
{
data: null,
title: "",
render: function (data, type, row) {
var drawingEdit = '@Url.Action("Edit", "Drawing")/' + row.Id;
return '<a href=\"' + drawingEdit + '\" class=\"btn btn-warning\">Edit</a>';
}
},
{
data: null,
title: "",
render: function (data, type, row) {
var drawingDelete = '@Url.Action("Delete", "Drawing")/' + row.Id;
return '<a href=\"' + drawingDelete + '\" class=\"btn btn-danger\">Delete</a>';
}
}
],
stateDuration: 0,
stateSave: true,
stateSaveCallback: function (settings, data) {
localStorage.setItem(`DataTables_${settings.sInstance}`, JSON.stringify(data));
},
stateLoadCallback: function (settings) {
return JSON.parse(localStorage.getItem(`DataTables_${settings.sInstance}`));
}
}),
});
</script>
我不想抓住所有 5k+ 值,而是只想获得前 10 个值。我尝试了以下解决方案,但我没有看到性能改进。我验证了它确实抓住了第一次抽奖(10 条记录)。
新操作:
public JsonResult LoadDrawings()
{
var search = Request.Form.GetValues("search[value]")[0];
var draw = Request.Form.GetValues("draw")[0];
var order = Request.Form.GetValues("order[0][column]")[0];
var orderDir = Request.Form.GetValues("order[0][dir]")[0];
var startRec = Convert.ToInt32(Request.Form.GetValues("start")[0]);
var pageSize = Convert.ToInt32(Request.Form.GetValues("length")[0]);
var data = _db.Drawings.ToList();
var totalRecords = data.Count;
if (!string.IsNullOrEmpty(search) && !string.IsNullOrWhiteSpace(search))
{
data = data.Where(d => d.DrawingNumber.ToString().Contains(search)
|| d.Drawer.Contains(search)
|| d.DrawingDate.ToString().Contains(search)
|| d.DrawingCategories.Any(c => c.Label.Contains(search))
|| d.Room.Label.Contains(search)
|| d.Notes.Contains(search)
|| d.Streets.Any(s => s.Street_.Contains(search))
|| d.Streets.Any(s => s.StreetCategories.Any(c => c.Label.Contains(search)))
|| d.Trs.Any(s => s.TrsSection.Label.Contains(search))
|| d.Trs.Any(t => t.TrsTownship.Label.Contains(search))
|| d.Trs.Any(r => r.TrsRanx.Label.Contains(search))).ToList();
}
/*if (!(string.IsNullOrEmpty(order) && string.IsNullOrEmpty(orderDir)))
{
data = data.OrderBy(order + " " + orderDir).ToList();
}*/
var recFilter = data.Count;
data = data.Skip(startRec).Take(pageSize).ToList();
var modifiedData = data.Select(d =>
new { d.DrawingNumber, d.Drawer, d.DrawingDate,
DrawingCategories = d.DrawingCategories.Select(c => c.Label).ToList(),
Room = d.Room.Label, d.Notes, Streets = d.Streets.Select(s => s.Street_).ToList(),
StreetCategories = d.Streets.Select(s => s.StreetCategories.Select(c => c.Label)).ToList(),
TrsSections = d.Trs.Select(s => s.TrsSection.Label).ToList(),
TrsTownships = d.Trs.Select(t => t.TrsTownship.Label).ToList(),
TrsRanges = d.Trs.Select(r => r.TrsRanx.Label).ToList(), d.Id });
return Json(new
{
draw = Convert.ToInt32(draw),
recordsTotal = totalRecords,
recordsFiltered = recFilter,
data = modifiedData
}, JsonRequestBehavior.AllowGet);
}
新的 DataTable 脚本:
<script>
$(document).ready(function () {
$("#DrawingDataTable").DataTable({
autoWidth: false,
deferRender: true,
order: [0, "desc"],
processing: true,
serverSide: true,
ajax: {
url: '@Url.Action("LoadDrawings", "Drawing")',
datatype: "json",
type: "POST"
},
columnDefs: [
{
targets: [3, 6, 7, 8, 9, 10],
searchable: true,
visible: false
},
{
targets: 11,
searchable: false,
visible: false
},
{
targets: [12, 13],
orderable: false,
searchable: false,
width: "1%"
},
{
targets: [1, 4, 5],
className: "uppercase"
}
],
columns: [
{
data: "DrawingNumber",
render: function (data, type, row) {
var drawingDetails = '@Url.Action("Details", "Drawing")/' + row.Id;
return '<a href=\"' + drawingDetails + '">' + data + '</a>';
}
},
{ data: "Drawer" },
{
data: "DrawingDate",
render: function (data) {
return moment(data).format("MM/DD/YYYY");
}
},
{ data: "DrawingCategories" },
{ data: "Room" },
{ data: "Notes" },
{ data: "Streets" },
{ data: "StreetCategories" },
{ data: "TrsSections" },
{ data: "TrsTownships" },
{ data: "TrsRanges" },
{ data: "Id" },
{
data: null,
title: "",
render: function (data, type, row) {
var drawingEdit = '@Url.Action("Edit", "Drawing")/' + row.Id;
return '<a href=\"' + drawingEdit + '\" class=\"btn btn-warning\">Edit</a>';
}
},
{
data: null,
title: "",
render: function (data, type, row) {
var drawingDelete = '@Url.Action("Delete", "Drawing")/' + row.Id;
return '<a href=\"' + drawingDelete + '\" class=\"btn btn-danger\">Delete</a>';
}
}
],
stateDuration: 0,
stateSave: true,
stateSaveCallback: function (settings, data) {
localStorage.setItem(`DataTables_${settings.sInstance}`, JSON.stringify(data));
},
stateLoadCallback: function (settings) {
return JSON.parse(localStorage.getItem(`DataTables_${settings.sInstance}`));
}
});
});
</script>
答:
0赞
Zee
3/16/2022
#1
加载数据时调用。
将整个数据集加载到内存中后,对整个数据集进行分页无助于提高性能。.ToList()
这样将加载整个表。 是你的朋友。它加载查询而不执行查询。.AsQueryable
public JsonResult LoadDrawings()
{
var search = Request.Form.GetValues("search[value]")[0];
var draw = Request.Form.GetValues("draw")[0];
var order = Request.Form.GetValues("order[0][column]")[0];
var orderDir = Request.Form.GetValues("order[0][dir]")[0];
var startRec = Convert.ToInt32(Request.Form.GetValues("start")[0]);
var pageSize = Convert.ToInt32(Request.Form.GetValues("length")[0]);
//var data = _db.Drawings.ToList();//This loads the entire table in memory
var data = _db.Drawings.AsQueryable(); //This builds a query.
if (!string.IsNullOrEmpty(search) && !string.IsNullOrWhiteSpace(search))
{
data = data.Where(d => d.DrawingNumber.ToString().Contains(search)
|| d.Drawer.Contains(search)
|| d.DrawingDate.ToString().Contains(search)
|| d.DrawingCategories.Any(c => c.Label.Contains(search))
|| d.Room.Label.Contains(search)
|| d.Notes.Contains(search)
|| d.Streets.Any(s => s.Street_.Contains(search))
|| d.Streets.Any(s => s.StreetCategories.Any(c => c.Label.Contains(search)))
|| d.Trs.Any(s => s.TrsSection.Label.Contains(search))
|| d.Trs.Any(t => t.TrsTownship.Label.Contains(search))
|| d.Trs.Any(r => r.TrsRanx.Label.Contains(search)))
//Replace this
.ToList()
//WIth this
.AsQueryable();
//Still A Query not executed to memory
}
var totalRecords = data.Count(); //Gets total Count of The query, This just executes a Select Count() from Table
var result = data.OrderBy(c => c.Drawer).Skip(startRec).Take(pageSize).ToList(); //The whole query is executed only on this line
评论
0赞
Zee
3/16/2022
更新了 Answer,单个查询,在调用 sql 时,获取 totalRecords 和记录。希望对你有所帮助。IQueryable 是用于分页、查询(尤其是使用多个参数)的绝佳工具
0赞
3/16/2022
对于 var myResult,我收到一条错误消息,在声明它之前无法使用局部变量 totalRecords。以及 myData 和记录在当前上下文中不存在。
0赞
Zee
3/16/2022
更新后,单个调用 LINQ 可能不起作用,它应该执行两个 SQL 语句,一个是 Select COunt(),另一个是分页查询。应该非常快
0赞
3/16/2022
是否有任何其他代码应该在 var 结果行下方?要退回什么?
0赞
Zee
3/16/2022
是的,您原始帖子中的其余代码。 用结果替换数据
评论