将一个简单的SQL组转换为LINQ(如何?)

时间:2014-06-10 12:27:59

标签: sql linq

在学习LINQ之后我觉得我还在犯错误。 这个特殊的简单SQL语句:

select APPL_COMPONENT_ID, TTEXT, count(*), count(distinct [USER])
from abi.dbo.data
where TASK='D' and [TCODE] <> 'SESSION_MANAGER'
group by APPL_COMPONENT_ID, TTEXT
order by APPL_COMPONENT_ID

我认为转换为这个LINQ:

var treeData =
            (from d in filteredQuery
             let groupColumns = new
             {
                 appCompId = d.APPL_COMPONENT_ID,
                 tText = d.TTEXT
             }
             where 
                String.Compare(d.TASK, "D") == 0
                && String.Compare(d.TCODE,"SESSION_MANAGER") != 0
             group d by groupColumns into gcs
             select new
             {
                 appCompId = gcs.Key.appCompId,
                 gcs.Key.tText,
                 noOfTransactions = gcs.Count(),
                 noOfUsers = gcs.Select(d => d.USER).Distinct().Count()
             }).OrderBy(d => d.appCompId);

但是生成的SQL(通过LINQ)要慢得多(慢400%)。 在调试检查时,它看起来像这样:

SELECT [t4].[APPL_COMPONENT_ID] AS [appCompId], [t4].[TTEXT] AS [tText], [t4].[value] AS [noOfTransactions], [t4].[value2] AS [noOfUsers]
FROM (
SELECT [t1].[APPL_COMPONENT_ID], [t1].[TTEXT], [t1].[value], (
    SELECT COUNT(*)
    FROM (
        SELECT DISTINCT [t2].[USER]
        FROM abi.[dbo].[data] AS [t2]
        WHERE 
        (
            (
                ([t1].[APPL_COMPONENT_ID] IS NULL) AND ([t2].[APPL_COMPONENT_ID] IS NULL)
            ) 
            OR 
            (
                ([t1].[APPL_COMPONENT_ID] IS NOT NULL) 
                AND ([t2].[APPL_COMPONENT_ID] IS NOT NULL) 
                AND 
                (
                    (([t1].[APPL_COMPONENT_ID] IS NULL) 
                    AND ([t2].[APPL_COMPONENT_ID] IS NULL)) 
                    OR 
                    (
                        ([t1].[APPL_COMPONENT_ID] IS NOT NULL) 
                        AND ([t2].[APPL_COMPONENT_ID] IS NOT NULL) 
                        AND ([t1].[APPL_COMPONENT_ID] = [t2].[APPL_COMPONENT_ID])
                    )
                )
            )
        ) 
        AND 
        (
            (
                ([t1].[TTEXT] IS NULL) AND ([t2].[TTEXT] IS NULL)
            ) 
            OR 
            (
                ([t1].[TTEXT] IS NOT NULL) 
                AND ([t2].[TTEXT] IS NOT NULL) 
                AND 
                (
                    (([t1].[TTEXT] IS NULL) AND ([t2].[TTEXT] IS NULL)) 
                    OR 
                    (
                        ([t1].[TTEXT] IS NOT NULL) 
                        AND ([t2].[TTEXT] IS NOT NULL) 
                        AND ([t1].[TTEXT] = [t2].[TTEXT])
                    )
                )
            )
        ) AND ([t2].[TASK] = 'D') AND ([t2].[TCODE] <> 'SESSION_MANAGER')
        ) AS [t3]
    ) AS [value2]
FROM (
    SELECT COUNT(*) AS [value], [t0].[APPL_COMPONENT_ID], [t0].[TTEXT]
    FROM abi.[dbo].[data] AS [t0]
    WHERE ([t0].[TASK] = 'D') AND ([t0].[TCODE] <> 'SESSION_MANAGER')
    GROUP BY [t0].[APPL_COMPONENT_ID], [t0].[TTEXT]
    ) AS [t1]
) AS [t4]
ORDER BY [t4].[APPL_COMPONENT_ID]

有谁知道指出我的错误? 谢谢!

2 个答案:

答案 0 :(得分:0)

我的查询为:

        var treeData = filteredQuery
            .Where(d => d.TASK.Equals("D"))
            .Where(d => !d.TCODE.Equals("SESSION_MANAGER"))
            .GroupBy(d => new { Component = d.APPL_COMPONENT_ID, Text = d.TTEXT })
            .Select(grp => new
            {
                appCompId = grp.Key.Component,
                tText = grp.Key.Text,
                noOfTransactions = grp.Count(),
                noOfUsers = grp.Select(d => d.USER).Distinct().Count()
            }).OrderBy(results => results.appCompId);

答案 1 :(得分:0)

我最终使用了这个技巧。 我知道它没有提供与所需LINQ解决方案相同的机制。但它在更短的时间内(<1秒)提供相同的结果。 问题分为两部分:

  1. 没有分组的LINQ。
  2. 使用词典在内存中完成分组。
  3. 那是:

    1. LINQ:

          var treeData = (
                  from d in filteredQuery
                  where d.TASK == "D"
                  where d.TCODE != "SESSION_MANAGER"
                  select new
                  {
                      d.APPL_COMPONENT_ID,
                      d.TTEXT,
                      d.USER
                  }
              );
          var dataList = treeData.ToList();
      
    2. 分组:

          Dictionary<String, DataNode> data = new Dictionary<String, DataNode>();
          foreach (var d in dataList)
          {
              //aggregation in Dictionary based on your data model
              ...
          }
      
    3. 注意:最终此解决方案快得多。它仍然是理想的解决方案。所以,我想,由于LINQ的限制,随着时间的推移发现了这种优化。