如何优化LINQ DB请求?

时间:2018-08-04 08:51:48

标签: c# linq

我有下一个代码,采用DB中元素的Last和Pre-Last参数:

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
     });

实际上是该部分:

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()

在1个请求中转换为这样的内容(仅显示一个块的一部分):

 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]

我不想多次重复同一部分:

conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Skip(1).Take(1)

所以,如果我这样做:

PrevBuffer = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Skip(1).Take(1).Select(                               
     param => new
     {

         param.MyPV,
         param.GroupPV,
         param.PerformanceBonusLevelId
     }
     ),

它将在输出中为每一行显示许多单独的请求,例如:

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

这部分也一样:

Tags = conts.Tags.Select(d=> d.UserTag.Emoji)

将获得多个选择,例如:

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]

可以通过某种方式对其进行优化吗?

3 个答案:

答案 0 :(得分:1)

做这样的事情将大大改善查询。

var result = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Take(2).ToArray();

PartnerPvPrev = result.Skip(1).Take(1).Select(x => x.MyPV).FirstOrDefault();
  GroupPvPrev = result.Skip(1).Take(1).Select(x => x.GroupPV).FirstOrDefault();
    LevelPrev = result.Skip(1).Take(1).Select(x => x.PerformanceBonusLevelId).FirstOrDefault();
    PartnerPv = result.Take(1).Select(x => x.MyPV).FirstOrDefault();
        Level = result.Take(1).Select(x => x.PerformanceBonusLevelId).FirstOrDefault();
      GroupPv = result.Take(1).Select(x => x.GroupPV).FirstOrDefault();

答案 1 :(得分:1)

您应该首先选择重复部分,然后在后续查询中使用它们。使用let关键字,这在查询语法中要容易得多:

var result = from conts in _context.Contacts
    where conts.CreatorUserId == _userManager.GetUserId(this.User)
    let monthsSorted = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth)
    let firstMonth = monthsSorted.FirstOrDefault()
    let prevMonth = monthsSorted.Skip(1).FirstOrDefault()
    select 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 = prevMonth.MyPV,
        GroupPvPrev = prevMonth.GroupPV,
        LevelPrev = prevMonth.PerformanceBonusLevelId,

        PartnerPv = firstMonth.MyPV,
        GroupPv = firstMonth.GroupPV,
        Level = firstMonth.PerformanceBonusLevelId,

        EntryDate = conts.NpaInfo.EntryDate,
        ExpirationDate = conts.NpaInfo.ExpirationDate
    };

答案 2 :(得分:0)

您应该使用GroupBy:

    class Program
    {
        static void Main(string[] args)
        {
            Conts conts = new Conts();

            List<NpaDatas> data = conts.NpaInfo.NpaDatas
                .OrderByDescending(x => x.DataMonth)
                .GroupBy(x => x.DataMonth).Select(x => x.FirstOrDefault()).ToList();

            //To get the second latest use followng
            NPaDatas results = data.Skip(1).FirstOrDefault();
        }
    }

    public class NpaDatas
    {
        public string NpaInfoId { get; set; }
        public DateTime DataMonth { get; set; }
        public PV PartnerPv { get; set; }
        public PV PerformanceBonusLevelId { get; set; }
        public PV GroupPv { get; set; }
    }
    public class PV
    {
        //data not specified 
    }
    public class Conts
    {
        public NpaInfo NpaInfo { get; set; }
    }
    public class NpaInfo
    {
        public string ID { get; set; }
        public List<NpaDatas> NpaDatas { get; set; }
    }