查询列表的每个元素的有效方法

时间:2015-08-10 21:05:32

标签: c# performance linq-to-entities

我必须遍历一组对象(比如说ID),并为每个对象执行一个特定的查询。例如:

IEnumerable<int> ids = getIDs(); //[1,2,3,4...]

现在我有了这个解决方案:

DBEntities db = new DBEntities();

var results =
    from a in db.TABLEA
    join b in db.TABLEB on a.id equals b.id
    join c in db.TABLEC on b.oid equals c.oid
    where ids.Contains(c.id)
    select a; 

但请记住,ID列表小于我搜索的表格。话虽这么说,上面的解决方案看起来效率低下,因为当我想要相反时,我正在寻找我的表中的每个记录与较小的列表。我也不想遍历列表,并且一次执行一个元素的查询。

理想情况下,我想要这样的事情:

DBEntities db = new DBEntities();
(some data structure) ids = getIDs();

var results =
    from a in db.TABLEA
    join b in db.TABLEB on a.id equals b.id
    join c in db.TABLEC on b.oid equals c.oid
    join i in ids on c.id equals i.id;

上面的(伪)代码将在一个查询中迭代我的列表元素,在单个查询中执行,并按列表的每个元素执行我的过滤器。

这是这样做的吗?如果是这样,实施此解决方案的适当数据结构是什么?如果没有,我有哪些替代方案?

2 个答案:

答案 0 :(得分:3)

如果这是linq2Sql(或Linq2Entites),您的唯一选择就像您的示例中一样1.您无法“加入”具有内存列表的表。您必须使用Contains。哪个将被翻译为
Where c.id IN(2,3,4,5,...) SQL查询

答案 1 :(得分:3)

马格努斯的回答是对的,但不对::)

技术上在较新版本的Entity Framework中你有两个选项(我偶然发现了这个)。 Contains当然,还有Join

加入一个本地类型的原始类型一直是可能的,但很快(在几十个元素之后)引发SqlException

  

SQL语句的某些部分嵌套太深。重写查询或将其分解为较小的查询。

EF尝试将本地列表转换为SQL中的临时表。这是非常重要的。它必须通过UNION构建表,每个返回1个元素的select语句。这就是它过去只有5个元素的样子!

....
INNER JOIN  (SELECT 
    [UnionAll3].[C1] AS [C1]
    FROM  (SELECT 
        [UnionAll2].[C1] AS [C1]
        FROM  (SELECT 
            [UnionAll1].[C1] AS [C1]
            FROM  (SELECT 
                1 AS [C1]
                FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]
            UNION ALL
                SELECT 
                2 AS [C1]
                FROM  ( SELECT 1 AS X ) AS [SingleRowTable2]) AS [UnionAll1]
        UNION ALL
            SELECT 
            3 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable3]) AS [UnionAll2]
    UNION ALL
        SELECT 
        4 AS [C1]
        FROM  ( SELECT 1 AS X ) AS [SingleRowTable4]) AS [UnionAll3]
UNION ALL
    SELECT 
    5 AS [C1]
    FROM  ( SELECT 1 AS X ) AS [SingleRowTable5]) AS [UnionAll4] ON ....

如您所见,如果仔细观察,UNION语句是嵌套的。嵌套水平很快变得太深,这使得这种方法几乎没用。

但是,目前SQL看起来像这样:

....
INNER JOIN  (SELECT 
    1 AS [C1]
    FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]
UNION ALL
    SELECT 
    2 AS [C1]
    FROM  ( SELECT 1 AS X ) AS [SingleRowTable2]
UNION ALL
    SELECT 
    3 AS [C1]
    FROM  ( SELECT 1 AS X ) AS [SingleRowTable3]
UNION ALL
    SELECT 
    4 AS [C1]
    FROM  ( SELECT 1 AS X ) AS [SingleRowTable4]
UNION ALL
    SELECT 
    5 AS [C1]
    FROM  ( SELECT 1 AS X ) AS [SingleRowTable5]) AS [UnionAll4] ON ....

仍然不是美女,但是嵌套被链接取代,列表可以包含数百个元素。

但是......(这就是为什么马格努斯的答案是正确的),它表现不佳。列表中包含2000个元素的简单测试使用join获得2.5秒,使用Contains获得.25s。因此,加入本地序列仍然没有实际案例。