Как я могу настроить этот запрос LINQ, чтобы избежать SORT, но при этом получить IEnumerable? - PullRequest
0 голосов
/ 13 июня 2018

У меня довольно простой запрос на продажу, который потенциально может вернуть более 100 тыс. Строк в любом заданном запросе.(Упрощенный) запрос linq выглядит следующим образом:

var query = from adi in _repo.AccountingDocumentItems

select new Sales
{
    TotalInclusive = adi.TotalInclusive,
    Employees = adi.Employees.Select(x => x.FirstName + " " + x.LastName)
};

Поскольку продажу можно назначить нескольким сотрудникам, и мне нужна эта информация - я перетаскиваю здесь строку имен IEnumerable, чтобы я мог позжесоедините их запятыми.

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

SELECT 
[Project1].[AccountingDocumentItemId] AS [AccountingDocumentItemId], 
[Project1].[C1] AS [C1], 
[Project1].[TotalInclusive] AS [TotalInclusive], 
[Project1].[C3] AS [C2], 
[Project1].[C2] AS [C3]
FROM ( SELECT 
    [Extent1].[AccountingDocumentItemId] AS [AccountingDocumentItemId], 
    [Extent1].[TotalInclusive] AS [TotalInclusive], 
    1 AS [C1], 
    CASE WHEN ([Join1].[AccountingDocumentItemId] IS NULL) THEN CAST(NULL AS varchar(1)) ELSE [Join1].[FirstName] + N' ' + [Join1].[LastName] END AS [C2], 
    CASE WHEN ([Join1].[AccountingDocumentItemId] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C3]
    FROM  [dbo].[AccountingDocumentItems] AS [Extent1]
    LEFT OUTER JOIN  (SELECT [Extent2].[AccountingDocumentItemId] AS [AccountingDocumentItemId], [Extent3].[FirstName] AS [FirstName], [Extent3].[LastName] AS [LastName]
        FROM  [dbo].[AccountingDocumentItemEmployees] AS [Extent2]
        INNER JOIN [dbo].[Employees] AS [Extent3] ON [Extent3].[EmployeeId] = [Extent2].[EmployeeId] ) AS [Join1] ON [Extent1].[AccountingDocumentItemId] = [Join1].[AccountingDocumentItemId]
)  AS [Project1]
ORDER BY [Project1].[AccountingDocumentItemId] ASC, [Project1].[C3] ASC

Обычно этохорошо, он выполняется довольно хорошо, но сортировка в этом запросе становится тем хуже, чем больше столбцов я пытаюсь получить.Таким образом, проблема в том, что SQL Server приходится выполнять очень дорогую операцию сортировки, особенно когда число строк начинает превышать 100 тыс.

Я бы хотел избежать этого, но я не вижу никакихДругой способ получить сотрудников за продажу.Я попытался сгруппировать по AccountingDocumentItemId, а затем сгруппировать в самом C #, но производительность для этого на 100k + строках ужасна.

Как я могу реструктурировать этот запрос, чтобы избежать сортировки, но при этом возвращать IEnumerable имен сотрудников

Ответы [ 2 ]

0 голосов
/ 13 июня 2018

Другим вариантом будет запрос базы данных один раз для каждой коллекции, а затем группа объединяет их вместе в памяти.Примерно так:

var query1 = _repo.AccountingDocumentItems.Select(x => new {x.TotalInclusive, x.Id}).AsEnumerable();
var query2 = _repo.Employees.Where(x => x.AccountingDocumentItems.Any()).Select(x => new {x.FirstName, x.LastName, x.AccId }).AsEnumerable();

var result = from x in query1
             join y in query2 on x.Id equals y.AccId into g
select new Sales
{
    TotalInclusive = x.TotalInclusive,
    Employees = g.Select(x => x.FirstName + " " + x.LastName)
}

Если он имеет лучшую производительность или изношен, вам придется тестировать.

0 голосов
/ 13 июня 2018

Сортировка существует для улучшения производительности материализации данных.Это связано с тем, что данные возвращаются в формате:

TotalInclusiveA, NameA
TotalInclusiveA, NameB
TotalInclusiveA, NameC
TotalInclusiveB, NameD
...

. Сортировка списка по TotalInclusive упрощает группирование их по totalInclusive и превращение имен в список.

Youесть два варианта.Первый вариант - изменить запрос так, чтобы группировка была одна на клиенте.Но вы сказали, что пробовали это, и это было медленно (очевидно, если вы тянете 100 тысяч строк).

Второй вариант - объединить имена в одну строку на клиенте.Но это не тривиально.Кажется, есть вариант , чтобы сделать это на MS SQL 2017 , но более старые версии могут потребовать некоторой хакерской реализации.И не может быть способа сделать это с простым LINQ.

...