This Any 比 this contains 好还是不好?
This Any is better or not than this contains?
我正在使用 EF6,我想获取 table 中的记录,这些记录在一组 ID 中。
例如,在我的测试中,我使用了 4 个 ID。
我尝试了两个选项,第一个是任意选项。
dbContext.MyTable
.Where(x => myIDS.Any(y=> y == x.MyID));
而这个 linq exrepsion 生成的 T-SQL 是:
SELECT
*
FROM [dbo].[MiTabla] AS [Extent1]
WHERE EXISTS (SELECT
1 AS [C1]
FROM (SELECT
[UnionAll2].[C1] AS [C1]
FROM (SELECT
[UnionAll1].[C1] AS [C1]
FROM (SELECT
cast(130 as bigint) AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]
UNION ALL
SELECT
cast(139 as bigint) AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable2]) AS [UnionAll1]
UNION ALL
SELECT
cast(140 as bigint) AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable3]) AS [UnionAll2]
UNION ALL
SELECT
cast(141 as bigint) AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable4]) AS [UnionAll3]
WHERE [UnionAll3].[C1] = [Extent1].[MiID]
)
怎么可以看出,T-SQL是一个"where exists",使用了很多子查询和联合。
第二个选项是包含。
dbContext.MyTable
.Where(x => myIDS.Contains(x.MiID));
而 T-SQL:
SELECT
*
FROM [dbo].[MiTabla] AS [Extent1]
WHERE [Extent1].[MiID] IN (cast(130 as bigint), cast(139 as bigint), cast(140 as bigint), cast(141 as bigint))
contains 被翻译成 "where in",但查询要简单得多。
我读到 any 它曾经更快,所以我怀疑 any 是否更快,虽然乍一看更复杂,但是否更快。
非常感谢。
编辑:我有一些测试(我不知道这是否是最好的测试方法)。
System.Diagnostics.Stopwatch miswContains = new System.Diagnostics.Stopwatch();
miswContains.Start();
for (int i = 0; i < 100; i++)
{
IQueryable<MyTable> iq = dbContext.MyTable
.Where(x => myIDS.Contains(x.MyID));
iq.ToArrayAsync();
}
miswContains.Stop();
System.Diagnostics.Stopwatch miswAny = new System.Diagnostics.Stopwatch();
miswAny.Start();
for (int i = 0; i < 20; i++)
{
IQueryable<MyTable> iq = dbContext.Mytable
.Where(x => myIDS.Any(y => y == x.MyID));
iq.ToArrayAsync();
}
miswAny.Stop();
结果是miswAny大约是850ms,miswContains大约是4251ms。
所以第二个选项,包含contaions,速度较慢。
如果您的 MiTabla.MiID
在 index 中,您的第二个选项是我能想到的最快的解决方案(至少对于不是很大的 id 数组)。
如果您想了解更多关于 in
子句性能的信息:Is SQL IN bad for performance?.
如果您知道 ID,那么使用 LINQ2SQL Count() 方法会创建更简洁、更快速的 SQL 代码(比 Any 和 Contains):
dbContext.MyTable
.Where(x => myIDS.Count(y=> y == x.MyID) > 0);
为计数生成的 SQL 应如下所示:
DECLARE @p0 Decimal(9,0) = 12345
SELECT COUNT(*) AS [value]
FROM [ids] AS [t0]
WHERE [t0].[id] = @p0
您可以从查询的形状看出 Any
根本不可扩展。不需要 myIDS
中的很多元素(大概 ~50 个)就可以得到 SQL 超出最大嵌套级别的异常。
Contains
在这方面要好得多。在其性能受到严重影响之前,它可以处理几千个元素。
所以我会选择可扩展的解决方案,即使 Any
对小数字可能更快。可以使 Contains
甚至 better scalable.
I have read that any it use to be faster,
在 LINQ-to-objects 中这通常是正确的,因为枚举在第一次命中时停止。但是对于针对 SQL 后端的 LINQ,生成的 SQL 才是最重要的。
我正在使用 EF6,我想获取 table 中的记录,这些记录在一组 ID 中。
例如,在我的测试中,我使用了 4 个 ID。
我尝试了两个选项,第一个是任意选项。
dbContext.MyTable
.Where(x => myIDS.Any(y=> y == x.MyID));
而这个 linq exrepsion 生成的 T-SQL 是:
SELECT
*
FROM [dbo].[MiTabla] AS [Extent1]
WHERE EXISTS (SELECT
1 AS [C1]
FROM (SELECT
[UnionAll2].[C1] AS [C1]
FROM (SELECT
[UnionAll1].[C1] AS [C1]
FROM (SELECT
cast(130 as bigint) AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]
UNION ALL
SELECT
cast(139 as bigint) AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable2]) AS [UnionAll1]
UNION ALL
SELECT
cast(140 as bigint) AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable3]) AS [UnionAll2]
UNION ALL
SELECT
cast(141 as bigint) AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable4]) AS [UnionAll3]
WHERE [UnionAll3].[C1] = [Extent1].[MiID]
)
怎么可以看出,T-SQL是一个"where exists",使用了很多子查询和联合。
第二个选项是包含。
dbContext.MyTable
.Where(x => myIDS.Contains(x.MiID));
而 T-SQL:
SELECT
*
FROM [dbo].[MiTabla] AS [Extent1]
WHERE [Extent1].[MiID] IN (cast(130 as bigint), cast(139 as bigint), cast(140 as bigint), cast(141 as bigint))
contains 被翻译成 "where in",但查询要简单得多。
我读到 any 它曾经更快,所以我怀疑 any 是否更快,虽然乍一看更复杂,但是否更快。
非常感谢。
编辑:我有一些测试(我不知道这是否是最好的测试方法)。
System.Diagnostics.Stopwatch miswContains = new System.Diagnostics.Stopwatch();
miswContains.Start();
for (int i = 0; i < 100; i++)
{
IQueryable<MyTable> iq = dbContext.MyTable
.Where(x => myIDS.Contains(x.MyID));
iq.ToArrayAsync();
}
miswContains.Stop();
System.Diagnostics.Stopwatch miswAny = new System.Diagnostics.Stopwatch();
miswAny.Start();
for (int i = 0; i < 20; i++)
{
IQueryable<MyTable> iq = dbContext.Mytable
.Where(x => myIDS.Any(y => y == x.MyID));
iq.ToArrayAsync();
}
miswAny.Stop();
结果是miswAny大约是850ms,miswContains大约是4251ms。
所以第二个选项,包含contaions,速度较慢。
如果您的 MiTabla.MiID
在 index 中,您的第二个选项是我能想到的最快的解决方案(至少对于不是很大的 id 数组)。
如果您想了解更多关于 in
子句性能的信息:Is SQL IN bad for performance?.
如果您知道 ID,那么使用 LINQ2SQL Count() 方法会创建更简洁、更快速的 SQL 代码(比 Any 和 Contains):
dbContext.MyTable
.Where(x => myIDS.Count(y=> y == x.MyID) > 0);
为计数生成的 SQL 应如下所示:
DECLARE @p0 Decimal(9,0) = 12345
SELECT COUNT(*) AS [value]
FROM [ids] AS [t0]
WHERE [t0].[id] = @p0
您可以从查询的形状看出 Any
根本不可扩展。不需要 myIDS
中的很多元素(大概 ~50 个)就可以得到 SQL 超出最大嵌套级别的异常。
Contains
在这方面要好得多。在其性能受到严重影响之前,它可以处理几千个元素。
所以我会选择可扩展的解决方案,即使 Any
对小数字可能更快。可以使 Contains
甚至 better scalable.
I have read that any it use to be faster,
在 LINQ-to-objects 中这通常是正确的,因为枚举在第一次命中时停止。但是对于针对 SQL 后端的 LINQ,生成的 SQL 才是最重要的。