Гость
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / Почему в Linq C# запрос выполняется медленнее, чем в LinqPAD? Как оптимизировать? / 4 сообщений из 4, страница 1 из 1
05.12.2013, 14:13
    #38490301
Osho
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему в Linq C# запрос выполняется медленнее, чем в LinqPAD? Как оптимизировать?
Я пишу приложение на asp.net с использованием Entity Framework. Все Linq-запросы пишу сначала в LinqPad, затем уже запрос вставляю в приложение.

Код: c#
1.
2.
3.
4.
5.
6.
UploadedFileCompanyRelations
.Where(x=>x.UploadedFileId == 670)
.SelectMany(x=>x.Company.CompanySales.Where(s=>s.ProductId==4))
.Select(x=>x.SaleTaskRelations
.OrderByDescending(t => t.Task.Startline)
.FirstOrDefault(t => t.Task.Type == 6))



Запрос к базе данных:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
DECLARE @Type INT
DECLARE @UploadedId INT
DECLARE @ProductId INT
DECLARE @Progress INT
DECLARE @BranchId INT
DECLARE @SaleProgress INT

SET @Type = 6
SET @UploadedId = 670
SET @ProductId = 4
SET @Progress = 3
SET @BranchId = 1
SET @SaleProgress = 0

--select COUNT(*)
select sOut.ProgressId, t.Progress, t.Type, sp.ProgressType
from dbo.UploadedFileCompanyRelations as ufc
inner join dbo.Sales as sOut on sOut.CompanyId = ufc.CompanyId
inner join dbo.Companies as c on c.Id = ufc.CompanyId
inner join dbo.SaleProgresses as sp on sp.Id = sOut.ProgressId
outer apply
(select TOP 1 t.Type, t.Progress from dbo.Sales as s 
inner join dbo.SaleTaskRelations as strs on strs.SaleId = s.Id
inner join dbo.Tasks as t on t.Id = strs.TaskId
Where s.Id = sOut.Id and t.Type = @Type
Order by t.Startline desc) as t
where ufc.UploadedFileId = @UploadedId 
and @ProductId = sOut.ProductId 
and t.Progress != @Progress
and c.ProviderId = @BranchId 
and sp.ProgressType != @SaleProgress



Что мне удалось выяснить: при написании запроса без
Код: c#
1.
2.
3.
.Select(x=>x.SaleTaskRelations
.OrderByDescending(t => t.Task.Startline)
.FirstOrDefault(t => t.Task.Type == 6))



работает так как в разы быстрее, но без этого куска я получаю просто Sales.

Второй вопрос как переписать
Код: c#
1.
2.
3.
.Select(x=>x.SaleTaskRelations
.OrderByDescending(t => t.Task.Startline)
.FirstOrDefault(t => t.Task.Type == 6))



чтобы он работал также как и
Код: sql
1.
outer apply

в запросе T-SQL. Необходимый участок бд, ниже в изображении.
Если необходима дополнительная инфа с удовольствием допишу.
...
Рейтинг: 0 / 0
05.12.2013, 15:15
    #38490425
Osho
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему в Linq C# запрос выполняется медленнее, чем в LinqPAD? Как оптимизировать?
Проблема решилась написанием sql-запроса в asp.net приложении:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
 var prId = new SqlParameter("@ProductId", productId);
            var fileId = new SqlParameter("@UploadedId", id);
            var tasktype = new SqlParameter("@Type", type);
            var brId = new SqlParameter("@BranchId", branchId);

            const string uncompleteQuery = "select COUNT(*) " +
                                 "from dbo.UploadedFileCompanyRelations as ufc " +
                                 "inner join dbo.Sales as sOut on sOut.CompanyId = ufc.CompanyId " +
                                 "inner join dbo.Companies as c on c.Id = ufc.CompanyId " +
                                 "inner join dbo.SaleProgresses as sp on sp.Id = sOut.ProgressId " +
                                 "outer apply " +
                                 "(select TOP 1 t.Type, t.Progress from dbo.Sales as s " +
                                 "inner join dbo.SaleTaskRelations as strs on strs.SaleId = s.Id " +
                                 "inner join dbo.Tasks as t on t.Id = strs.TaskId " +
                                 "Where s.Id = sOut.Id and t.Type = @Type " +
                                 "Order by t.Startline desc) as t " +
                                 "where ufc.UploadedFileId = @UploadedId " +
                                 "and @ProductId = sOut.ProductId " +
                                 "and c.ProviderId = @BranchId " ;

            var uncompleteStoredProcedure = _context.Database.SqlQuery<int>(uncompleteQuery + "and t.Progress != 3", new SqlParameter("@ProductId", productId), new SqlParameter("@UploadedId", id), new SqlParameter("@Type", type), new SqlParameter("@BranchId", branchId));

            var positiveStoredProcedure = _context.Database.SqlQuery<int>(uncompleteQuery + "and t.Progress = 3 and sp.ProgressType = 0", new SqlParameter("@ProductId", productId), new SqlParameter("@UploadedId", id), new SqlParameter("@Type", type), new SqlParameter("@BranchId", branchId));

            var unpositiveStoredProcedure = _context.Database.SqlQuery<int>(uncompleteQuery + "and t.Progress = 3 and sp.ProgressType != 0", new SqlParameter("@ProductId", productId), new SqlParameter("@UploadedId", id), new SqlParameter("@Type", type), new SqlParameter("@BranchId", branchId));



Код сам по себе громоздкий и местами нечитабельный, но теперь та же страница загружается за 1 секунду против 1,7 минуты:)
Неужели все настолько плохо в Linq C#?
...
Рейтинг: 0 / 0
06.12.2013, 09:38
    #38491294
handmadeFromRu
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему в Linq C# запрос выполняется медленнее, чем в LinqPAD? Как оптимизировать?
Osho,
ну вы смотрели какой запрос то выходит после вашего Linq?

а так по теме как замутить OUTER APPLY
http://stackoverflow.com/questions/3014362/c-sharp-outer-apply-in-linq
...
Рейтинг: 0 / 0
06.12.2013, 12:21
    #38491537
Osho
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему в Linq C# запрос выполняется медленнее, чем в LinqPAD? Как оптимизировать?
handmadeFromRu,

Полный запрос Linq выглядит так:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
UploadedFileCompanyRelations
.Where(x=>x.UploadedFileId == 670)
.SelectMany(x=>x.Company.CompanySales.Where(s=>s.ProductId==4))
.Select(x=>x.SaleTaskRelations
.OrderByDescending(t => t.Task.Startline)
.FirstOrDefault(t => t.Task.Type == 6))
.Where(x=>x.Task!=null)
.Select(x=>x.Task)
.Where(x=>x.Progress != 3)



Запрос Linq C# к базе:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
SELECT 
[GroupBy1].[A1] AS [C1]
FROM ( SELECT 
	COUNT(1) AS [A1]
	FROM     (SELECT 
		[Extent2].[Id] AS [Id]
		FROM  [dbo].[UploadedFileCompanyRelations] AS [Extent1]
		INNER JOIN [dbo].[Sales] AS [Extent2] ON ([Extent1].[CompanyId] = [Extent2].[CompanyId]) AND ( CAST( [Extent2].[ProductId] AS int) = @p__linq__1)
		WHERE [Extent1].[UploadedFileId] = @p__linq__0 ) AS [Project1]
	OUTER APPLY  (SELECT TOP (1) 
		[Extent3].[SaleId] AS [SaleId], 
		[Extent3].[TaskId] AS [TaskId], 
		[Extent4].[Id] AS [Id], 
		[Extent4].[Type] AS [Type]
		FROM  [dbo].[SaleTaskRelations] AS [Extent3]
		INNER JOIN [dbo].[Tasks] AS [Extent4] ON [Extent3].[TaskId] = [Extent4].[Id]
		WHERE ([Project1].[Id] = [Extent3].[SaleId]) AND ( CAST( [Extent4].[Type] AS int) = @p__linq__2) ) AS [Element1]
	INNER JOIN [dbo].[Tasks] AS [Extent5] ON [Element1].[TaskId] = [Extent5].[Id]
	LEFT OUTER JOIN [dbo].[Tasks] AS [Extent6] ON [Element1].[TaskId] = [Extent6].[Id]
	WHERE 3 <>  CAST( [Extent6].[Progress] AS int)
)  AS [GroupBy1]',N'@p__linq__1 int,@p__linq__0 int,@p__linq__2 int',@p__linq__1=4,@p__linq__0=670,@p__linq__2=3



В LinqPad:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
SELECT [t5].[Id], [t5].[AuthorId], [t5].[ResponsibleId], [t5].[DeptId], [t5].[FromDeptId], [t5].[Created], [t5].[Startline], [t5].[Assigned], [t5].[Completed], [t5].[Type], [t5].[Progress], [t5].[Body], [t5].[Number], [t5].[Ammount], [t5].[Renewal], [t5].[Period], [t5].[Payment], [t5].[Importance]
FROM [UploadedFileCompanyRelations] AS [t0]
INNER JOIN [Companies] AS [t1] ON [t1].[Id] = [t0].[CompanyId]
CROSS JOIN [Sales] AS [t2]
OUTER APPLY (
    SELECT TOP (1) [t4].[Id], [t4].[AuthorId], [t4].[ResponsibleId], [t4].[DeptId], [t4].[FromDeptId], [t4].[Created], [t4].[Startline], [t4].[Assigned], [t4].[Completed], [t4].[Type], [t4].[Progress], [t4].[Body], [t4].[Number], [t4].[Ammount], [t4].[Renewal], [t4].[Period], [t4].[Payment], [t4].[Importance]
    FROM [SaleTaskRelations] AS [t3]
    INNER JOIN [Tasks] AS [t4] ON [t4].[Id] = [t3].[TaskId]
    WHERE ([t4].[Type] = @p0) AND ([t3].[SaleId] = [t2].[Id])
    ORDER BY [t4].[Startline] DESC
    ) AS [t5]
WHERE ([t5].[Progress] <> @p1) AND ([t0].[UploadedFileId] = @p2) AND ([t2].[ProductId] = @p3) AND ([t2].[CompanyId] = [t1].[Id])
ORDER BY [t5].[Startline] DESC



За статью спасибо, но, к сожалению, там разбирается пример когда две таблицы соединены связью один-ко-многим, у меня связь Tasks - SaleTaskRelation - Sales. Поэтому приходится извращаться с множеством select.

Я переписал было запрос c GroupJoin, но запрос выполняется так же медленно, но при этом получаем кучу select в самом запросе SQL.

Запрос с GroupJoin:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
UploadedFileCompanyRelations
.Where(x=>x.UploadedFileId == 670)
.SelectMany(x=>x.Company.CompanySales.Where(s=>s.ProductId==4))
.GroupJoin(SaleTaskRelations, x => x.Id, strs => strs.SaleId,
                        (x, strs) => new { 
						progressType = x.Progress.ProgressType, 
						task = strs.OrderByDescending(t => t.Task.Startline)
                                .FirstOrDefault(t => t.Task.Type == 1).Task 
								}).Where(x=>x.task!= null)
...
Рейтинг: 0 / 0
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / Почему в Linq C# запрос выполняется медленнее, чем в LinqPAD? Как оптимизировать? / 4 сообщений из 4, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]