LINQ의 가장 좋은 조회를 실체에 쓰는 8가지 팁과 기교

LINQ는 강력한 검색 도구입니다.NET 응용 프로그램.조회를 작성할 때 신속하고 효과적으로 실행될 수 있도록 일부 기술을 따라야 한다.다음은 실체의 성능을 향상시키기 위해 LINQ가 고려해야 할 몇 가지 사항입니다.
  • 필요한 기둥만 당기기
  • IQueryable 및 Skip/Take 사용
  • 오른쪽에서 왼쪽 연결 및 내부 연결 사용
  • AsNoTracking() 사용
  • 대량 데이터 삽입
  • 솔리드에서 비동기식 작업
  • 일치하지 않는 매개변수 찾기
  • 데이터베이스에 제출된 SQL 쿼리 확인
  • 필요한 열만 당겨요.


    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();
        }
    }
    
    SQL
    exec 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();
    }
    

    엔티티에서 비동기식 작업 사용


    엔티티는 다음과 같은 비동기식 작업을 제공합니다.
  • ToListAsync(): 비동기식 데이터 컬렉션 검색
  • Countasync(): 비동기식 검색 데이터 개수입니다.
  • FirstAsync(): 첫 번째 데이터 세트를 비동기적으로 검색합니다.
  • SaveChangesAsync(): 비동기적으로 엔티티 변경 사항을 저장합니다.
  • 비동기식 작업은 UI 스레드의 장애를 줄이기 위해 응용 프로그램의 특정 위치에 사용됩니다.그것들은 사용자 인터페이스가 응답성을 가지도록 함으로써 사용자 인터페이스를 강화한다.
    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를 사용하는 것을 고려해 보십시오.
    다음과 같이 가정합니다.
  • 방 책상은 호텔의 방 목록을 수용할 것이다.
  • RoomProducts 테이블은 Room의 제품 목록을 포함하고 Room을 참조합니다.Id는 외부 키로 사용됩니다.
  • 브랜드 테이블에는 RoomProducts 브랜드가 포함되며 RoomProducts를 참조합니다.Id는 외부 키로 사용됩니다.
  • 모든 세 표의 기록은 틀림없이 하나의 관계 기록이 있을 것이다.
  • 모든 테이블을 join으로 비추고 일치하는 기록을 추출하는 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여 개의 사용자 정의 컨트롤을 제공합니다.어플리케이션 개발에서 다음을 참조하여 사용하십시오.
  • ASP.NET Core
  • ASP.NET MVC
  • Angular
  • Blazor
  • React
  • Vue
  • JavaScript
  • Flutter
  • Xamarin
  • WPF
  • UWP
  • WinForms
  • 만약 저희 구성 요소에 대해 궁금한 점이 있거나 해명할 필요가 있다면, 아래의 논평에서 알려주십시오.저희support forum,Direct-Trac 또는feedback portal을 통해 연락하실 수 있습니다.우리는 기꺼이 당신을 도울 것입니다!
    게시물8 Tips and Tricks for Writing the Best Queries in LINQ to Entities이 먼저 Syncfusion Blogs에 올라왔다.

    좋은 웹페이지 즐겨찾기