Linq to sql - Оптимальный способ вернуть подмножество записей И общее количество записей - PullRequest
0 голосов
/ 16 декабря 2010

Я смотрел на некоторый код linq to SQL, который используется для таблицы с постраничной загрузкой.В нем необходимо вернуть подмножество записей и общее количество записей в базе данных.Код выглядит следующим образом:

var query = (from p in MyTable select new {p.HostCable, p.PatchingSet});
int total = query.ToList().Count;
query = query.Skip(5).Take(10);

Я хотел бы немного покопаться в том, что происходит при выполнении этого, я вижу, что происходит 2 запроса - один для получения ВСЕХ строк из БД, и один для получения подмножества,Само собой разумеется, что влияние получения всех отчетов на производительность не очень хорошее.Я предполагаю, что «ToList» заставляет запрос быть выполненным, тогда метод Count запускается для всего List.

Если переформулировать оператор, чтобы сделать его более эффективным - это моя улучшенная версия:

int total = MyTable.Count();
var query = (from p in MyTable select new {p.HostCable, p.PatchingSet}).Skip(5).Take(10);

Это приводит к попаданию SQL для "Select count ..", а затем к SQLхит для фактического выбора записей.

Это оптимально, есть ли лучшие решения?

Спасибо!

Ответы [ 2 ]

2 голосов
/ 06 мая 2013

Из того, что я видел, это невозможно в LINQ to SQL без небольшого взлома.

Я обнаружил, что этот метод работает.Краткая сводка этого метода: я преобразую объект IQueryable в объект команды и изменяю текст команды, чтобы включить общее количество в набор результатов.Исходный SQL-запрос конвертера LINQ to SQL использует синтаксис ROW_NUMBER() OVER() для разбиения на строки, я просто добавляю COUNT(*) OVER(), чтобы получить общее количество.

Добавьте этот метод в свой класс DataContext.

public IEnumerable<TWithTotal> ExecutePagedQuery<T, TWithTotal>(IQueryable<T> query, int pageSize, int pageNumber, out int count)
    where TWithTotal : IWithTotal
{
    var cmd = this.GetCommand(query.Skip(pageSize * pageNumber).Take(pageSize));
    var commandText = cmd.CommandText.Replace("SELECT ROW_NUMBER() OVER", "SELECT COUNT(*) OVER() AS TOTALROWS, ROW_NUMBER() OVER");
    commandText = "SELECT TOTALROWS AS TotalCount," + commandText.Remove(0, 6);
    cmd.CommandText = commandText;

    var reader = cmd.ExecuteReader();

    var list = this.Translate<TWithTotal>(reader).ToList();

    if (list.Count > 0)
        count = list[0].TotalCount;
    else
        count = 0;

    return list;
}

Вам нужно будет создать новый класс, который содержит все свойства исходного объекта, реализующего интерфейс IWithTotal.

ОБНОВЛЕНИЕ: Вы не можете смешивать сопоставленные инесопоставленные столбцы в LINQ to SQL.

public interface IWithTotal
{
    int TotalCount { get; set; }
}

public class Project : IWithTotal
{
    public int TotalCount { get; set; }
    public int ProjectID { get; set; }
    public string Name { get; set; }
}

DataContext.Translate предъявляет некоторые требования, поэтому убедитесь, что ваш запрос удовлетворяет этим требованиям, если у вас есть какие-либо проблемы.На сложности запроса, вы должны увидеть увеличение производительности.Ниже приведены показатели тестирования, которое я провел с запросом подсчета, постраничным запросом выбора и постраничным выбором с запросом подсчета.Проценты - это стоимость запроса относительно пакета.

Count - 6%
Select with paging - 47%
Select with paging + Count - 48%
1 голос
/ 16 декабря 2010
int total = query.Count();

Вместо того, чтобы выбирать все, а затем делать подсчет объектов в памяти, он выполнит подсчет через запрос и просто вернет это число, которое должно быть намного быстрее.

В ответ на ваше обновление я не думаю, что вы получите намного лучший способ сделать это. В конечном итоге он сводится к двум запросам: один для получения общего количества записей, а другой для получения их подмножества.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...