LINQ의 가장 좋은 조회를 실체에 쓰는 8가지 팁과 기교
39959 단어 csharpsqlproductivitydotnet
필요한 열만 당겨요.
LINQ를 사용할 때는 테이블의 모든 열을 불러오는 대신 Select 자구에 필요한 열만 끌어옵니다.
다음 LINQ 질의를 고려하십시오.
using (var context = new LINQEntities())
{
var fileCollection = context.FileRepository.Where(a => a.IsDeleted == false).ToList();
}
이 질의는 다음 화면 캡처와 같이 SQL로 컴파일됩니다.SQL로 컴파일된 질의
비록 우리는 단지 몇 개의 열만 필요로 할 수 있지만, 우리는 이미 모든 열을 불러왔다.이것은 필요한 메모리를 초과하여 소모하고 조회 실행 속도를 늦출 것이다.더 잘 집행하기 위해서, 우리는 아래와 같이 조회를 변경할 수 있다.
using (var context = new LINQEntities())
{
var fileCollection = context.FileRepository.Where(a => a.IsDeleted == false).
Select(a => new
{
FilePath = a.FilePath
}
).ToList();
}
이 질의는 다음 화면 캡처와 같이 최적화된 방식으로 SQL로 컴파일됩니다.쿼리를 보다 효율적인 SQL로 컴파일
IQueryable 및 Skip/Take 사용
대량의 데이터를 처리하고 테이블이나 격자 컨트롤러와 연결할 때, 사용자의 모든 기록을 하나의 실례에 불러와서는 안 됩니다. 시간이 오래 걸리기 때문입니다.
반대로, 우리는 먼저 일정한 수량의 기록을 불러올 수 있다. 예를 들어 10개나 20개이다.사용자가 다음 기록을 보려고 할 때, 우리는 필요에 따라 10개나 20개의 기록을 불러올 수 있다.
C#의 IQueryable 형식은 계산되지 않은 SQL 조회를 저장할 수 있으며, 나중에 skip과 take를 적용한 후 데이터 집합으로 변환하여 실행할 수 있습니다.
C#
private IEnumerable<object> LoadAllFiles(int skip, int take,string fileRevision,string fileNumber)
{
using (var context = new LINQEntities())
{
//Select and perform join on the needed tables and build an IQueryable collection
IQueryable<FileRepository> fileCollection = context.FileRepository;
//Build queries dynamically over Queryable collection
if(!string.IsNullOrEmpty(fileRevision))
fileCollection = fileCollection.Where(a => a.FileRevision == fileRevision && a.IsDeleted == false);
//Build queries dynamically over Queryable collection
if (!string.IsNullOrEmpty(fileNumber))
fileCollection = fileCollection.Where(a => a.FileRevision == fileNumber && a.IsDeleted == false);
//Apply skip and take and load records
return fileCollection.OrderBy(a=>a.Id).Skip(()=>skip).Take(()=>take).Select(a=>new
{
FileIssuedBy=a.FileIssuedBy
}).ToList();
}
}
SQLexec sp_executesql N'SELECT
[Project1].[C1] as [C1],
[Project1].[FileIssuedBy] as [FileIssuedBy],
FROM (SELECT
[Extent1].[Id] as [Id],
[Extent1].[FileIssuedBy] as [FileIssuedBy],
1 as [C1]
FROM [dbo].[FileRepository] as [Extent1]
WHERE ([Extent1].[FileRevision] = @p_linq_0) AND (0=[Extent1].[IsDeleted]) AND ([Extent1].[FileRevision] = @p_linq_1)
AND (0=[Extent1].[IsDeleted])) AS [Project1]
ORDER BY row_number() OVER (ORDER BY [Project1].[Id] ASC)
OFFSET @p_linq_2 ROWS FETCH NEXT @p_linq_3 ROWS ONLY ',N'@p_linq_0 nvarchar(4000),@p_linq_1 nvarchar(4000),
@p_linq_2 int,@p_linq_3
int',@p_linq_0=N'A',@p_linq_1=N'A',@p_pinq_2=0,@p_linq_3=10
팁: LINQ 질의를 생략하고 수락할 때 다음 사항을 고려하여 더 나은 성능을 얻으십시오.오른쪽 위치에서 왼쪽 연결 및 내부 연결 사용
왼쪽 연결과 내부 연결을 응용하는 곳에서도 조회 실행이 중요한 역할을 한다.우리가 표 A의 기록이 표 B의 기록과 일치하는지 확인하지 못할 때, 우리는 왼쪽 연결을 사용해야 한다.우리가 두 표에 모두 관계 기록이 있다고 확정할 때, 우리는 내부 연결을 사용해야 한다.
정확한 연결 형식을 선택하여 테이블 간의 관계를 구축하는 것은 매우 중요하다. 내부 연결 조회가 있는 여러 테이블이 왼쪽 연결이 있는 여러 테이블보다 더 잘 실행되기 때문이다.
따라서 우리는 우리의 요구를 확인하고 연결 (왼쪽 또는 안쪽) 을 사용하여 조회를 더욱 잘 실행해야 한다.
AsNoTracking() 사용
우리가 LINQ를 통해 기록을 데이터베이스에서 실체 조회로 불러올 때, 우리는 그것들을 처리하여 데이터베이스로 갱신할 것이다.이를 위해서는 실체를 추적해야 한다.
우리가 읽기 작업만 수행할 때, 우리는 데이터베이스에 대해 어떠한 업데이트도 하지 않지만, 실체는 우리가 데이터베이스에 대해 업데이트를 하고 해당하는 처리를 할 것이라고 가정할 것이다.따라서 우리는 AsNoTracking()을 사용하여 실체의 가설과 처리를 제한하여 실체가 추적할 메모리의 양을 줄일 수 있다.
using (var context = new LINQEntities())
{
var fileCollection = context.FileRepository.AsNoTracking().Where(a => a.IsDeleted == false).
Select(a => new
{
FilePath = a.FilePath
}
).ToList();
}
대량 데이터 삽입
또 다른 고려 사항은 대량 데이터 삽입을 처리할 때, 예를 들어 SQL 테이블에 수백 개 또는 수천 개의 기록을 추가하는 것이다.
using (var context = new LINQEntities())
{
for(int i=1;i<=1000;i++)
{
var file = new FileRepository { FilePath=""+i+"",FileDescription=""+i+""};
context.FileRepository.Add(file);
}
context.SaveChanges();
}
이전 코드 예시에서 FilesRepository에 새 엔티티를 추가할 때마다 데이터에서 변경 사항이 감지됩니다 ().실체핵심이 터치되고 조회 실행이 느려집니다.이 문제를 해결하려면 대량 삽입에 가장 적합한 AddRange를 사용하십시오.EF 6.0에 AddRange를 도입하여 단일 데이터베이스 왕복에 삽입하여 성능 비용을 줄일 수 있습니다.아래에 수정된 코드를 보세요.
using (var context = new LINQEntities())
{
var fileCollection = new List<FileRepository>();
for(int i=1;i<=1000;i++)
{
var file = new FileRepository { FilePath=""+i+"",FileDescription=""+i+""};
fileCollection.Add(file);
}
context.FileRepository.AddRange(fileCollection);
context.SaveChanges();
}
엔티티에서 비동기식 작업 사용
엔티티는 다음과 같은 비동기식 작업을 제공합니다.
using (var context = new LINQEntities())
{
var countAsync = context.FileRepository.CountAsync();
var listAsync = context.FileRepository.ToListAsync();
var firstAsync = context.FileRepository.FirstAsync();
context.SaveChangesAsync();
}
일치하지 않는 매개변수 찾기
조회할 때 데이터 형식이 일치하지 않을 수 있습니다. 이것은 LINQ를 사용하여 실체에 접근할 때 대량의 시간 소모를 초래합니다.하나의 장면을 고려하면, 하나의 표에 File Number가 열거되어 있으며, 이것은 varchar 형식으로 10글자를 수용할 수 있다.따라서varchar(10) 데이터 형식으로 표시됩니다.
FileNumber 필드 값이 File1에 일치하는 레코드를 로드해야 합니다.
using (var context = new LINQEntities())
{
string fileNumber = "File1";
var fileCollection = context.FileRepository.Where(a => a.FileNumber == fileNumber).ToList();
}
SQL이전 화면 캡처에서 강조 표시된 부분에서, 우리가 전달한 변수가 SQL에서 nvarchar(4000)로 선언되었고, 표열에서 우리의 열 형식은 varchar(10)로 표시됩니다.따라서 매개변수 유형이 일치하지 않으므로 SQL은 내부적으로 변환을 수행합니다.
이 매개 변수가 일치하지 않는 문제를 극복하기 위해서, 우리는 아래 코드에서 속성 이름이 있는 열의 유형을 언급해야 한다.
public string FilePath { get; set; }
[Column(TypeName = "varchar")]
public string FileNumber { get; set; }
이제 SQL 매개변수 유형이 varchar로 생성됩니다.데이터베이스에 제출된 SQL 쿼리 확인
LINQ에서 실체 조회까지의 성능을 향상시키려고 할 때, SQL 조회를 데이터베이스에 제출하기 전에 그것을 검사하는 것이 가장 중요하다.우리는 LINQ to Entities 쿼리가 SQL 쿼리로 변환되고 데이터베이스에 대해 실행된다는 것을 알고 있다.LINQ 쿼리의 결과로 생성된 SQL 쿼리는 성능을 효과적으로 향상시킬 수 있습니다.
우리 예를 하나 봅시다.룸, RoomProducts, Brands 사이에서 내비게이션 LINQ를 사용하는 것을 고려해 보십시오.
다음과 같이 가정합니다.
C#
using (var context = new LINQEntities())
{
var roomCollection = context.Rooms.
Include(x => x.RoomProducts).Select
(x => x.RoomProducts.Select(a => a.Brands)).
ToList();
}
우리는 방, RoomProducts, 브랜드 집합을 얻고 있다.질의의 등가 SQL은 다음 코드에 표시됩니다.SQL
SELECT
[Project1].[Id] AS [Id],
[Project1].[C2] AS [C1],
[Project1].[Id1] AS [Id1],
[Project1].[C1] AS [C2],
[Project1].[Id2] AS [Id2],
[Project1].[Brand] AS [Brand],
[Project1].[RoomProductsParentId] AS [RoomProductsParentId],
[Project1].[IsDeleted] AS [IsDeleted],
[Project1].[ModifiedDate] AS [ModifiedDate],
[Project1].[ModifiedBy] AS [ModifiedBy]
FROM ( SELECT
[Extent1].[Id] AS [Id],
[Join1].[Id1] AS [Id1],
[Join1].[Id2] AS [Id2],
[Join1].[Brand] AS [Brand],
[Join1].[RoomProductsParentId] AS [RoomProductsParentId],
[Join1].[IsDeleted1] AS [IsDeleted],
[Join1].[ModifiedDate1] AS [ModifiedDate],
[Join1].[ModifiedBy1] AS [ModifiedBy],
CASE WHEN ([Join1].[Id1] IS NULL) THEN CAST(NULL AS int) WHEN ([Join1].[Id2] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1],
CASE WHEN ([Join1].[Id1] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2]
FROM [dbo].[Rooms] AS [Extent1]
LEFT OUTER JOIN (SELECT [Extent2].[Id] AS [Id1], [Extent2].[RoomParentId] AS [RoomParentId], [Extent3].[Id] AS [Id2], [Extent3].[Brand] AS [Brand], [Extent3].[RoomProductsParentId] AS [RoomProductsParentId], [Extent3].[IsDeleted] AS [IsDeleted1], [Extent3].[ModifiedDate] AS [ModifiedDate1], [Extent3].[ModifiedBy] AS [ModifiedBy1]
FROM [dbo].[RoomProducts] AS [Extent2]
LEFT OUTER JOIN [dbo].[Brands] AS [Extent3] ON [Extent2].[Id] = [Extent3].[RoomProductsParentId] ) AS [Join1] ON [Extent1].[Id] = [Join1].[RoomParentId]
) AS [Project1]
ORDER BY [Project1].[Id] ASC, [Project1].[C2] ASC, [Project1].[Id1] ASC, [Project1].[C1] ASC
네비게이션 속성의 일부로 생성된 검색은 왼쪽 외부 연결을 사용하여 테이블 간의 관계를 구축하고 모든 열을 불러오는 것을 볼 수 있습니다.내부 연결 조회에 비해 왼쪽 외부 연결로 이루어진 조회의 운행이 느리다.우리는 이 세 개의 표에 틀림없이 관계가 있다는 것을 알고 있기 때문에, 이 조회를 좀 수정합시다.
C#
using (var context = new LINQEntities())
{
var roomCollection = (from room in context.Rooms
join products in context.RoomProducts on room.Id equals products.RoomParentId
join brands in context.Brands on products.Id equals brands.RoomProductsParentId
select new
{
Room = room.Room,
Product = products.RoomProduct,
Brand = brands.Brand
}).ToList();
}
그러면 다음과 같은 결과가 발생합니다.SQL
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Room] AS [Room],
[Extent2].[RoomProduct] AS [RoomProduct],
[Extent3].[Brand] AS [Brand]
FROM [dbo].[Rooms] AS [Extent1]
INNER JOIN [dbo].[RoomProducts] AS [Extent2] ON [Extent1].[Id] = [Extent2].[RoomParentId]
INNER JOIN [dbo].[Brands] AS [Extent3] ON [Extent2].[Id] = [Extent3].[RoomProductsParentId]
현재 코드가 더 깨끗해 보이고 실행 속도가 이전의 시도보다 빠르다.결론
이 박문에서 우리는 LINQ를 실체 성능까지 향상시키는 데 집중할 수 있는 분야를 보았다.우리는 이 문장이 당신에게 도움이 되기를 바랍니다.
Syncfusion은 개발자가 다양한 플랫폼에서 작업하는 것을 간소화하기 위해 1000여 개의 사용자 정의 컨트롤을 제공합니다.어플리케이션 개발에서 다음을 참조하여 사용하십시오.
게시물8 Tips and Tricks for Writing the Best Queries in LINQ to Entities이 먼저 Syncfusion Blogs에 올라왔다.
Reference
이 문제에 관하여(LINQ의 가장 좋은 조회를 실체에 쓰는 8가지 팁과 기교), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/syncfusion/8-tips-and-tricks-for-writing-the-best-queries-in-linq-to-entities-20c0텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)