업데이트 3 : 이 발표 에 따르면 EF6 알파 2의 EF 팀이이 문제를 해결했습니다.
업데이트 2 :이 문제를 해결하기위한 제안을 만들었습니다. 투표하려면 여기로 이동하세요 .
하나의 매우 간단한 테이블이있는 SQL 데이터베이스를 고려하십시오.
CREATE TABLE Main (Id INT PRIMARY KEY)
테이블을 10,000 개의 레코드로 채 웁니다.
WITH Numbers AS
(
SELECT 1 AS Id
UNION ALL
SELECT Id + 1 AS Id FROM Numbers WHERE Id <= 10000
)
INSERT Main (Id)
SELECT Id FROM Numbers
OPTION (MAXRECURSION 0)
테이블에 대한 EF 모델을 빌드하고 LINQPad에서 다음 쿼리를 실행합니다 ( "C # Statements"모드를 사용하므로 LINQPad가 자동으로 덤프를 생성하지 않습니다).
var rows =
Main
.ToArray();
실행 시간은 ~ 0.07 초입니다. 이제 Contains 연산자를 추가하고 쿼리를 다시 실행합니다.
var ids = Main.Select(a => a.Id).ToArray();
var rows =
Main
.Where (a => ids.Contains(a.Id))
.ToArray();
이 경우 실행 시간은 20.14 초 (288 배 느림)입니다!
처음에는 쿼리를 위해 내 보낸 T-SQL이 실행하는 데 시간이 더 오래 걸린다고 생각했기 때문에 LINQPad의 SQL 창에서 잘라내어 SQL Server Management Studio로 붙여 넣었습니다.
SET NOCOUNT ON
SET STATISTICS TIME ON
SELECT
[Extent1].[Id] AS [Id]
FROM [dbo].[Primary] AS [Extent1]
WHERE [Extent1].[Id] IN (1,2,3,4,5,6,7,8,...
결과는
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 88 ms.
다음으로 LINQPad가 문제의 원인이라고 생각했지만 LINQPad에서 실행하든 콘솔 애플리케이션에서 실행하든 성능은 동일합니다.
따라서 문제는 Entity Framework 내 어딘가에있는 것으로 보입니다.
내가 여기서 뭔가 잘못하고 있니? 이것은 내 코드에서 시간이 중요한 부분이므로 성능을 높이기 위해 할 수있는 일이 있습니까?
Entity Framework 4.1 및 Sql Server 2008 R2를 사용하고 있습니다.
업데이트 1 :
아래 토론에는 EF가 초기 쿼리를 작성하는 동안 지연이 발생했는지 아니면 다시받은 데이터를 구문 분석하는 동안 발생했는지에 대한 몇 가지 질문이있었습니다. 이것을 테스트하기 위해 다음 코드를 실행했습니다.
var ids = Main.Select(a => a.Id).ToArray();
var rows =
(ObjectQuery<MainRow>)
Main
.Where (a => ids.Contains(a.Id));
var sql = rows.ToTraceString();
이는 EF가 데이터베이스에 대해 실행하지 않고 쿼리를 생성하도록합니다. 그 결과이 코드를 실행하는 데 ~ 20 개의 secord가 필요하므로 초기 쿼리를 작성하는 데 거의 모든 시간이 소요되는 것으로 보입니다.
CompiledQuery를 구출하려면? 그리 빠르지 않습니다. CompiledQuery는 쿼리에 전달 된 매개 변수가 기본 유형 (int, string, float 등)이어야합니다. 배열 또는 IEnumerable을 허용하지 않으므로 ID 목록에 사용할 수 없습니다.
var qry = Main.Where (a => ids.Contains(a.Id)); var rows = qry.ToArray();
쿼리의 어느 부분이 시간이 걸리는지 확인 하려고 했습니까 ?