Это вопрос, связанный с C# MVC2 Jqgrid - what is the correct way to do server side paging?, где я спросил и нашел, как повысить производительность для запроса в таблице с примерно 2000 строк. Производительность была улучшена с 10 секунд до 1 секунды.C# Entity Framework + Linq - как вы ускоряете медленный запрос?
Теперь я пытаюсь выполнить тот же запрос, где таблица содержит 20 000 строк - и запрос занимает 30 секунд. Как я могу улучшить его дальше? 20 тыс. Рядов по-прежнему невелики.
Некоторые возможные идеи я являются:
- может быть улучшена за счет денормализацию для удаления соединений и подводит
- сделать вид и запрос, который вместо того, чтобы запрашивать и присоединение к таблице
- Дон 't запрашивать всю таблицу, сначала выберите фильтр (например, фильтр A | B | C .. etc)
- Добавить индексы в таблицы
- Что-то еще?
Это действие MVC, который занимает 30 секунд, 20 тысяч строк: (параметры снабжены jqgrid, где sidx = какой столбец сортировки, и Sord = порядок сортировки)
public ActionResult GetProductList(int page, int rows, string sidx, string sord,
string searchOper, string searchField, string searchString)
{
if (sidx == "Id") { sidx = "ProductCode"; }
var pagedData = _productService.GetPaged(sidx, sord, page, rows);
var model = (from p in pagedData.Page<Product>()
select new
{
p.Id, p.ProductCode, p.ProductDescription,
Barcode = p.Barcode ?? string.Empty,
UnitOfMeasure = p.UnitOfMeasure != null ? p.UnitOfMeasure.Name : "",
p.PackSize,
AllocatedQty = p.WarehouseProducts.Sum(wp => wp.AllocatedQuantity),
QtyOnHand = p.WarehouseProducts.Sum(wp => wp.OnHandQuantity)
});
var jsonData = new
{
Total = pagedData.TotalPages, Page = pagedData.PageNumber,
Records = pagedData.RecordCount, Rows = model
};
return Json(jsonData, JsonRequestBehavior.AllowGet);
}
ProductService .GetPaged() вызывает ProductRepository.GetPaged, который вызывает genericRepository.GetPaged(), который делает это:
public ListPage GetPaged(string sidx, string sord, int page, int rows)
{
var list = GetQuery().OrderBy(sidx + " " + sord);
int totalRecords = list.Count();
var listPage = new ListPage
{
TotalPages = (totalRecords + rows - 1)/rows,
PageNumber = page,
RecordCount = totalRecords,
};
listPage.SetPageData(list
.Skip((page > 0 ? page - 1 : 0) * rows)
.Take(rows).AsQueryable());
return listPage;
}
The() пункт .OrderBy использует LinqExtensions, так что я могу передать строку вместо предиката - может й замедляет его?
И наконец ListPage это просто класс для удобного подведению свойства, jqgrid потребности пейджинга:
public class ListPage
{
private IQueryable _data;
public int TotalPages { get; set; }
public int PageNumber { get; set; }
public int RecordCount { get; set; }
public void SetPageData<T>(IQueryable<T> data)
{
_data = data;
}
public IQueryable<T> Page<T>()
{
return (IQueryable<T>)_data;
}
}
GetQuery является:
public IQueryable<T> GetQuery()
{
return ObjectSet.AsQueryable();
}
Обычай метод .OrderBy состоит из этих двух методов :
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source,
string ordering, params object[] values)
{
return (IQueryable<T>)OrderBy((IQueryable)source, ordering, values);
}
public static IQueryable OrderBy(this IQueryable source, string ordering,
params object[] values)
{
if (source == null) throw new ArgumentNullException("source");
if (ordering == null) throw new ArgumentNullException("ordering");
ParameterExpression[] parameters = new ParameterExpression[] {
Expression.Parameter(source.ElementType, "") };
ExpressionParser parser = new ExpressionParser(parameters, ordering, values);
IEnumerable<DynamicOrdering> orderings = parser.ParseOrdering();
Expression queryExpr = source.Expression;
string methodAsc = "OrderBy";
string methodDesc = "OrderByDescending";
foreach (DynamicOrdering o in orderings)
{
queryExpr = Expression.Call(
typeof(Queryable), o.Ascending ? methodAsc : methodDesc,
new Type[] { source.ElementType, o.Selector.Type },
queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters)));
methodAsc = "ThenBy";
methodDesc = "ThenByDescending";
}
return source.Provider.CreateQuery(queryExpr);
}
С редактированием я очень смущен относительно того, как он возвращается к универсальному коду, когда этот OrderBy использует не общий код ... вы можете уточнить? я пропущу что-то очевидное? –
Извините, я не уверен, что вы просите - этот 'OrderBy()' - это метод расширения, определенный в другом классе. –
Ну, 'GetQuery()' собирается возвратить 'IQueryable' (generic); 'GetQuery(). OrderBy (sidx +" "+ sord)' (используя метод, который вы показываете) будет 'IQueryable' (не общий). AFAIK не существует 'Skip (...)' etc * defined * для не-generic ... не уверен, как это будет работать? –