2014-03-07 2 views
0

두 시나리오의 성능에 대한 질문이 있으며 더 빠를 것입니다.SQL Server의 계산 된 함수와 메모리 목록의 성능

옵션 # 1

내가 원하는 해달라고 것들, 예를 제거하고 메모리와 사용 C#의 모든 여행 보고서의 목록을 잡아 빠르게 될 것이다 :

var travelReports = db.TravelReports.Include("ApprovalStatuses") 
      .Where(s => s.IsDeleted == false).ToList(); 
      travelReports.RemoveAll(s => s.Status == TravelReportStatus.Draft); 
      travelReports.RemoveAll(s => s.Status == TravelReportStatus.NeedsInformation); 

있는 케이스에 상태는 승인 상태를 사용하여 NotMapped 재산 및 게터를 사용하여 모델에 계산 될 것 같은 :

if (ApprovalStatuses.Count == 0) 
{ 
    return TravelReportStatus.Draft; 
} 
else if (JobRoles.All(j => ApprovalStatuses.Any(a => a.Role == j && a.Status == ApprovalStatus.Approved))) 
{ 
    return TravelReportStatus.Processed; 
} 
else if (ApprovalStatuses.Any(s => s.Status == ApprovalStatus.Denied)) 
{ 
    return TravelReportStatus.Denied; 
} 
else 
{ 
    return TravelReportStatus.PendingApproval; 
} 

옵션 # 2 S 내 모델에 기능을 넣어 QL을 호출하고 열을 호출하십시오. 상태 :

CREATE FUNCTION dbo.GetTravelReportStatus(@travelReportId int) 
RETURNS int 
AS 
-- Returns a Enum Int Value of the Status -- 
BEGIN 

DECLARE @value int; 
DECLARE @count int; 
DECLARE @isReject int = 0; 
SELECT @isReject = Count(*) FROM dbo.Approvals WHERE TravelReportId = @travelReportId and Status = 3; 
SELECT @count = Count(*) FROM dbo.Approvals WHERE TravelReportId = @travelReportId; 
SELECT @value = 
CASE 
WHEN @isReject > 0 THEN 3 
WHEN @isReject = 0 and @count = 0 THEN 1 
WHEN @isReject = 0 and @count > 0 and @count < 6 THEN 2 
WHEN @isReject = 0 and @count >= 6 THEN 4 
END; 
return @value; 
END; 


Sql("ALTER TABLE dbo.TravelReports ADD Status AS dbo.GetTravelReportStatus(Id)"); 

그리고 나서 SQL과 엔터티 프레임 워크를 사용하여 원하는 상태의 여행 보고서 만 가져옵니다.

var travelReports = db.TravelReports.Include("ApprovalStatuses") 
       .Where(s => s.Status == TravelReportStatus.PendingApproval || s.Status == TravelReportStatus.Processed || s.Status == TravelReportStatus.Denied) 
       .Where(s => s.IsDeleted == false).ToList(); 

여행 보고서는 계속 증가하지만 약 4 년 후에는 보관 저장소로 이동하고 더 이상 데이터베이스에 저장되지 않습니다.

제 질문은 옵션 1 또는 옵션 2가 최고의 성능을 제공합니까? 옵션 2는 여행 보고서를 요청할 때마다 2 회의 쿼리를 통해 데이터베이스에 도달합니까? 그래서 사용자 25 Travel Reports를 반환하면 상태를 계산하기 위해 데이터베이스를^2 번 방문 할 것입니다. CodeFirst EF에서이를 중지시키는 방법이 있습니까?

+0

"모든 여행 보고서 목록을 메모리에 저장하고 C#을 사용하여 내가 원하지 않는 목록을 빨리 삭제할 수 있습니까?" 당신의 테이블이 아주 작지 않은 한. –

+0

제목을 편집했습니다. "[제목에"태그 "가 포함되어 있어야합니까?] (http://meta.stackexchange.com/questions/19190/)"합의가 "아니오, 그렇지 않아야합니다"로 표시되어야합니다. –

+0

제목에 대해 미안 해요, 나는 그것을 미래에 볼 것입니다 :) –

답변

0

EF가 데이터베이스에 3 번이나 도달할지 여부는 알 수 없지만 let 절이 해결되면 한 번만 기록됩니다.

var travelReports = (from s in db.TravelReports.Include("ApprovalStatuses") 
        let status = s.Status 
        where (status == TravelReportStatus.PendingApproval || 
          status == TravelReportStatus.Processed || 
          status == TravelReportStatus.Denied) && 
          reports.IsDeleted == false 
        select reports).ToList(); 

대신 쿼리 구문의 방법 구문을 사용하여 let 절을 다시 만드는 것은 훨씬 더 어려워하는 것입니다. 값의 컨테이너 역할을하는 익명 형식을 만들어야합니다. 이 간단한 쿼리의 경우 너무 어렵지는 않지만 더 복잡한 쿼리를 사용하면 쿼리 구문을 사용하는 것이 더 쉬울 수 있습니다.

var travelReports = db.TravelReports.Include("ApprovalStatuses") 
       .Select(s => new {Query = s, Status = s.Status}) //Project to a new object that has the status pre-calculated 
       .Where(s => s.Status == TravelReportStatus.PendingApproval || s.Status == TravelReportStatus.Processed || s.Status == TravelReportStatus.Denied) 
       .Select(s => s.Query) //flatten the object back out. 
       .Where(s => s.IsDeleted == false) 
       .ToList(); 

P.S. EF가 어떤 쿼리를 생성하는지 알아 내려면 .ToString()을 IQueryable 개체에 넣고 서버에 보낼 SQL을 반환합니다.

var travelReportsQuery = db.TravelReports.Include("ApprovalStatuses") 
       .Where(s => s.Status == TravelReportStatus.PendingApproval || s.Status == TravelReportStatus.Processed || s.Status == TravelReportStatus.Denied) 
       .Where(s => s.IsDeleted == false) 

var travelReportsQueryText = travelReportsQuery.ToString(); 
var travelReports = travelReportsQuery.ToList(); 
+0

감사합니다. 나는 toString을 점검 할 것이다! 내가 여분의 시간에 서버를 치는 것에 대해 물어 보았을 때 나는 테이블의 계산 된 필드를 의미하고 그 함수는 테이블을 두 번 치는 것을 의미합니다. 당신이 제안한 것처럼 쿼리에서 Status를 사용하려면 EF에 필드가 있어야하지만 여전히 최상의 성능을 발휘할 수 있을지 확실하지 않습니다. –