Rac*_*hel 5 c# linq-to-entities entity-framework sql-server-2005
是否有替代使用.Contains()
选择实体框架中存在于指定列表中的对象?Contains()
如果您的列表很小,那么效果很好,但是一旦您开始获得几千个项目,性能就会很糟糕.
return (from item in context.Accounts
where accountIdList.Contains(item.AccountId)
select item).ToList();
Run Code Online (Sandbox Code Playgroud)
我正在使用EF 4.0,.Net Framework 4.0和SQL Server 2005.我不反对SQL解决方案,因为EF生成的查询只需要一秒钟就SQL运行大约10k项目.
我找到了一个替代方案,它使用 SQL 存储过程和参数的逗号分隔字符串在大约一秒内运行。比 EF 使用 5 分钟以上的时间要好得多.Contains()
它是使用以下命令从我的代码运行的:
string commaDelmitedList = string.Join(",", accountIdList);
return context.GetAccountsByList(commaDelmitedList).ToList();
Run Code Online (Sandbox Code Playgroud)
StoredProcedure(简化)如下所示:
SELECT *
FROM Accounts as T1 WITH (NOLOCK)
INNER JOIN (
SELECT Num FROM dbo.StringToNumSet(@commaDelimitedAccountIds, ',')
) as [T2] ON [T1].[AccountId] = [T2].[num]
Run Code Online (Sandbox Code Playgroud)
用户定义的函数dbo.StringToNumSet()
如下所示:
CREATE FUNCTION [dbo].[StringToNumSet] (
@TargetString varchar(MAX),
@SearchChar varchar(1)
)
RETURNS @Set TABLE (
num int not null
)
AS
BEGIN
DECLARE @SearchCharPos int, @LastSearchCharPos int
SET @SearchCharPos = 0
WHILE 1=1
BEGIN
SET @LastSearchCharPos = @SearchCharPos
SET @SearchCharPos = CHARINDEX( @SearchChar, @TargetString, @SearchCharPos + 1 )
IF @SearchCharPos = 0
BEGIN
INSERT @Set( num ) VALUES ( SUBSTRING( @TargetString, @LastSearchCharPos + 1, DATALENGTH( @TargetString ) ) )
BREAK
END
ELSE
INSERT @Set( num ) VALUES ( SUBSTRING( @TargetString, @LastSearchCharPos + 1, @SearchCharPos - @LastSearchCharPos - 1 ) )
END
RETURN
END
Run Code Online (Sandbox Code Playgroud)