美文网首页一步一坑
关于linq语句得一些隐藏bug分析

关于linq语句得一些隐藏bug分析

作者: 易兒善 | 来源:发表于2018-12-29 18:20 被阅读28次

    Contains

    table.Where(m=>datas.Contains (m=>m.Id)) 
    

    上面得这段代码换转换成类似下面这样得sql

    select * from table where Id in (...datas)
    

    看上去没问题,通常使用情况下也是没有问题。突然有一天数据库返回一个错误,说你得查询语句太复杂了,然你优化。这时候你就要检查一下datas得长度。有人说是1000,有人说是转换后1000个字节得长度。反正数据库就是罢工了。

    委托

    这样定义一个委托。

            public bool Any(Func<Storage, bool> predicate) {
                return _storageRepository.GetAll().Any(predicate);
            }
    
    

    然后这样调用。

     _service.Any(m => m.UserId == 123);
    

    本身没有什么问题。当Storage这张表数据量较少时也没什么问题。当数据量在几十万,几百万时,发现上面语句执行得很慢,甚至得不到结果而超时。
    与直接调用以下语句并不是一回事。

    _storageRepository.GetAll().Any(m => m.UserId == 123);
    

    list多条件查询

                var storages = StorageRepository.GetAll();
                var result = from user in users
                             join storage in storages
                             on new{userId = user.Id, orgId = user.OrgId}  
                             equals new {userId =storage.UserId, orgId = storage.OrgId } 
                             where  storage.Quantity>0
                             select storage ;
    

    上面得语句同样在表storage数据量小得时候很方便查询,但是数据量大得情况下并不奏效了。因为时将storages得数据全部取到内存中做得比较。这种多条件查询可以添加 userId-OrgId 关键字进行查询。

    FirstOrDefault

    from c in Storages
    group c by new {c.OrgId,c.ProductId}  into gStorage
    select new {
         id = gStorage.FirstOrDefault().Id,
         gStorage.Key.OrgId,
         gStorage.Key.ProductId,
         Quantity = gStorage.Sum(n => n.Quantity)
         
    }
    

    这样得linq 会转换成如下sql语句

    SELECT (
        SELECT [t3].[Id]
        FROM (
            SELECT TOP (1) [t2].[Id]
            FROM [Storage] AS [t2]
            WHERE ([t1].[OrgId] = [t2].[OrgId]) AND ([t1].[ProductId] = [t2].[ProductId])
            ) AS [t3]
        ) AS [id], [t1].[OrgId], [t1].[ProductId], [t1].[value] AS [Quantity]
    FROM (
        SELECT SUM([t0].[Quantity]) AS [value], [t0].[OrgId], [t0].[ProductId]
        FROM  [Storage] AS [t0]
        GROUP BY [t0].[OrgId], [t0].[ProductId]
        ) AS [t1]
    
    

    但是在很多情况下都不会这样转换。在复杂的linq中,数据量大的情况下,很有可能超时查不出数据来。
    建议修改为,效率是完全不一样的。

    from c in Storages
    group c by new {c.OrgId,c.ProductId}  into gStorage
    select new {
         id = gStorage.Min(n => n.Id),
         gStorage.Key.OrgId,
         gStorage.Key.ProductId,
         Quantity = gStorage.Sum(n => n.Quantity)
         
    }
    

    相关文章

      网友评论

        本文标题:关于linq语句得一些隐藏bug分析

        本文链接:https://www.haomeiwen.com/subject/ceqikqtx.html