查询列表中每个元素的有效方法
Efficient way to query each element of a list
我必须遍历一组对象(比方说 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 列表小于我正在搜索的 table。话虽这么说,上面的解决方案似乎效率低下,因为当我想要相反的时候,我正在寻找我的 table 的每条记录对一个较小的列表。我也不想遍历列表,一次只对一个元素执行查询。
理想情况下,我想要这样的东西:
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;
上面的(伪)代码将在单个查询中迭代我的列表元素,在单个查询中执行此操作并按列表的每个元素执行我的过滤器。
是这样吗?如果是这样,实施该解决方案的适当数据结构是什么?如果没有,我有哪些选择?
如果这是 linq2Sql(或 Linq2Entites),您唯一的选择就是在您的示例 1 中。您不能 "join" 具有内存列表的 table。你必须使用 Contains
。这将被翻译成
Where c.id IN(2,3,4,5,...)
SQL 查询
Magnus 的回答是正确的但不正确:)
技术上 在 Entity Framework 的较新版本中您确实有两个选项(我偶然发现了这一点)。 Contains
当然还有 Join
.
加入原始类型的本地序列一直是可能的,但很快(在几十个元素之后)引发了 SqlException
:
Some part of your SQL statement is nested too deeply. Rewrite the query or break it up into smaller queries.
EF 尝试将本地列表转换为 SQL 中的临时列表 table。令人惊讶的是,这并不平凡。它必须通过 UNION
-ing select 语句构建 table,每个 return 1 个元素。这是过去只有 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 ....
仍然不是很漂亮,但是嵌套被链式取代并且列表可以包含数百个元素。
但是...(这就是为什么 Magnus 的回答是正确的),它表现不佳。列表中包含 2000 个元素的简单测试使用 join
花费了 2.5 秒,使用 Contains
花费了 .25 秒。所以仍然没有用本地序列连接的实际案例。
我必须遍历一组对象(比方说 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 列表小于我正在搜索的 table。话虽这么说,上面的解决方案似乎效率低下,因为当我想要相反的时候,我正在寻找我的 table 的每条记录对一个较小的列表。我也不想遍历列表,一次只对一个元素执行查询。
理想情况下,我想要这样的东西:
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;
上面的(伪)代码将在单个查询中迭代我的列表元素,在单个查询中执行此操作并按列表的每个元素执行我的过滤器。
是这样吗?如果是这样,实施该解决方案的适当数据结构是什么?如果没有,我有哪些选择?
如果这是 linq2Sql(或 Linq2Entites),您唯一的选择就是在您的示例 1 中。您不能 "join" 具有内存列表的 table。你必须使用 Contains
。这将被翻译成 Where c.id IN(2,3,4,5,...)
SQL 查询
Magnus 的回答是正确的但不正确:)
技术上 在 Entity Framework 的较新版本中您确实有两个选项(我偶然发现了这一点)。 Contains
当然还有 Join
.
加入原始类型的本地序列一直是可能的,但很快(在几十个元素之后)引发了 SqlException
:
Some part of your SQL statement is nested too deeply. Rewrite the query or break it up into smaller queries.
EF 尝试将本地列表转换为 SQL 中的临时列表 table。令人惊讶的是,这并不平凡。它必须通过 UNION
-ing select 语句构建 table,每个 return 1 个元素。这是过去只有 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 ....
仍然不是很漂亮,但是嵌套被链式取代并且列表可以包含数百个元素。
但是...(这就是为什么 Magnus 的回答是正确的),它表现不佳。列表中包含 2000 个元素的简单测试使用 join
花费了 2.5 秒,使用 Contains
花费了 .25 秒。所以仍然没有用本地序列连接的实际案例。