I have next code, taking Last and Pre-Last params of elemensts in DB:
var result = _context.Contacts.Where(conts => conts.CreatorUserId == _userManager.GetUserId(this.User))
.Select(conts => new
{
conts.ID,
conts.Mobile,
conts.Email,
conts.Facebook,
conts.StateId,
conts.CreatorUserId,
conts.Birthday,
conts.Description,
conts.Name,
conts.Photo,
conts.SecondName,
Tags = conts.Tags.Select(d=> d.UserTag.Emoji),
NpaId = conts.NpaInfo.NpaId,
PartnerPvPrev = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Skip(1).Take(1).Select(x => x.MyPV).FirstOrDefault(),
GroupPvPrev = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Skip(1).Take(1).Select(x => x.GroupPV).FirstOrDefault(),
LevelPrev = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Skip(1).Take(1).Select(x => x.PerformanceBonusLevelId).FirstOrDefault(),
PartnerPv = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Take(1).Select(x => x.MyPV).FirstOrDefault(),
Level = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Take(1).Select(x => x.PerformanceBonusLevelId).FirstOrDefault(),// conts.NpaInfo.PerformanceBonusLevelId,
GroupPv = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Take(1).Select(x => x.GroupPV).FirstOrDefault(),
EntryDate = conts.NpaInfo.EntryDate,
ExpirationDate = conts.NpaInfo.ExpirationDate
});
In fact the part :
PartnerPvPrev = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Skip(1).Take(1).Select(x => x.MyPV).FirstOrDefault(),
GroupPvPrev = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Skip(1).Take(1).Select(x => x.GroupPV).FirstOrDefault(),
LevelPrev = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Skip(1).Take(1).Select(x => x.PerformanceBonusLevelId).FirstOrDefault()
converts to something like this in 1 request (show you only part for one block):
SELECT TOP(1) [t0].[MyPV]
FROM (
SELECT [x0].[MyPV], [x0].[DataMonth]
FROM [NpaDatas] AS [x0]
WHERE [conts.NpaInfo].[ID] = [x0].[NpaInfoId]
ORDER BY [x0].[DataMonth] DESC
OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY
) AS [t0]
ORDER BY [t0].[DataMonth] DESC
) AS [PartnerPvPrev], (
SELECT TOP(1) [t1].[GroupPV]
FROM (
SELECT [x1].[GroupPV], [x1].[DataMonth]
FROM [NpaDatas] AS [x1]
WHERE [conts.NpaInfo].[ID] = [x1].[NpaInfoId]
ORDER BY [x1].[DataMonth] DESC
OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY
) AS [t1]
ORDER BY [t1].[DataMonth] DESC
) AS [GroupPvPrev], (
SELECT TOP(1) [t2].[PerformanceBonusLevelId]
FROM (
SELECT [x2].[PerformanceBonusLevelId], [x2].[DataMonth]
FROM [NpaDatas] AS [x2]
WHERE [conts.NpaInfo].[ID] = [x2].[NpaInfoId]
ORDER BY [x2].[DataMonth] DESC
OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY
) AS [t2]
ORDER BY [t2].[DataMonth] DESC
) AS [LevelPrev]
I dont want to repeat the same part multiple times:
conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Skip(1).Take(1)
So, if I do like this :
PrevBuffer = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Skip(1).Take(1).Select(
param => new
{
param.MyPV,
param.GroupPV,
param.PerformanceBonusLevelId
}
),
It will display many separate requests in output for each row like:
SELECT [x0].[MyPV], [x0].[GroupPV], [x0].[PerformanceBonusLevelId]
FROM [NpaDatas] AS [x0]
WHERE @_outer_ID1 = [x0].[NpaInfoId]
ORDER BY [x0].[DataMonth] DESC
OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY
The same is about this part :
Tags = conts.Tags.Select(d=> d.UserTag.Emoji)
Will get multiple selects like:
SELECT [d.UserTag].[Emoji]
FROM [ContactTags] AS [d]
LEFT JOIN [UserTags] AS [d.UserTag] ON [d].[UserTagId] = [d.UserTag].[ID]
WHERE @_outer_ID = [d].[ContactId]
Can it be optimized somehow?
Skip(1).Take(1)and then laterTake(1)you could try combining to a single query ofTake(2)and then perform the logic client side (there may exist aTake(2)solution that's all Db side, I don't know)... That would cut your total queries in half at the very leastnewanonymous object creation. All of the hard DB works happens outside of this and that would be what we need to see to optimise the query.