복붙노트

[SQL] 페이징을 구현하는 효율적인 방법

SQL

페이징을 구현하는 효율적인 방법

내가 LINQ의 건너 뛰기 (사용) 및 페이징 () 메소드를 타고, 또는 SQL 쿼리 내 자신의 페이징을 구현해야 하는가?

가장 효율적인 어느입니까? 이유는 다른 통해 하나를 선택할 것인가?

나는 SQL 서버 2008, ASP.NET MVC 및 LINQ를 사용하고 있습니다.

해결법

  1. ==============================

    1.당신은 스킵 (N) .take (m) (데이터베이스 서버와 SQL 2,008분의 2,005 포함) 쿼리가 선택 ROW_NUMBER () 이상을 사용하는 것입니다 LINQ 메소드를 실행하면, 당신의 의심에 당신에게 간단한 답변을 제공하기 위해 노력 .. . 문의 SQL 엔진에서 직접 페이징이 어떻게 든 함께.

    당신은 스킵 (N) .take (m) (데이터베이스 서버와 SQL 2,008분의 2,005 포함) 쿼리가 선택 ROW_NUMBER () 이상을 사용하는 것입니다 LINQ 메소드를 실행하면, 당신의 의심에 당신에게 간단한 답변을 제공하기 위해 노력 .. . 문의 SQL 엔진에서 직접 페이징이 어떻게 든 함께.

    예를 하나 들어주기, 나는 mtcity라는 DB 테이블을하고 난 (엔티티 일뿐만 아니라와 LINQ) 다음 쿼리를 썼다 :

    using (DataClasses1DataContext c = new DataClasses1DataContext())
    {
        var query = (from MtCity2 c1 in c.MtCity2s
                    select c1).Skip(3).Take(3);
        //Doing something with the query.
    }
    

    그 결과 쿼리는 다음과 같습니다

    SELECT [t1].[CodCity], 
        [t1].[CodCountry], 
        [t1].[CodRegion], 
        [t1].[Name],  
        [t1].[Code]
    FROM (
        SELECT ROW_NUMBER() OVER (
            ORDER BY [t0].[CodCity], 
            [t0].[CodCountry], 
            [t0].[CodRegion], 
            [t0].[Name],
            [t0].[Code]) AS [ROW_NUMBER], 
            [t0].[CodCity], 
            [t0].[CodCountry], 
            [t0].[CodRegion], 
            [t0].[Name],
            [t0].[Code]
        FROM [dbo].[MtCity] AS [t0]
        ) AS [t1]
    WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p0 + @p1
    ORDER BY [t1].[ROW_NUMBER]
    

    창있는 데이터 액세스가 어느 (아주 아주 태초부터 데이터를 반환되며 조건이 충족 될만큼 테이블에 액세스 할 BTW 사촌, 냉각). 이것은 매우 유사합니다 :

    With CityEntities As 
    (
        Select ROW_NUMBER() Over (Order By CodCity) As Row,
            CodCity //here is only accessed by the Index as CodCity is the primary
        From dbo.mtcity
    )
    Select [t0].[CodCity], 
            [t0].[CodCountry], 
            [t0].[CodRegion], 
            [t0].[Name],
            [t0].[Code]
    From CityEntities c
    Inner Join dbo.MtCity t0 on c.CodCity = t0.CodCity
    Where c.Row Between @p0 + 1 AND @p0 + @p1
    Order By c.Row Asc
    

    이 데이터 액세스 윈도우를 생성하기 위해 배타적으로 인덱스를 사용하기 때문에, 두 번째 질의는 LINQ 결과보다 더 빠르게 실행될 제외; 당신은 몇 가지 필터링을해야하는 경우이 수단은, 필터링이 있어야한다 (또는이어야 함) 엔티티에 목록 (행이 생성되는 경우) 및 일부 인덱스는 좋은 성능을 유지하기 위해뿐만 아니라 만들어야합니다.

    이제, 더 나은 뭐죠?

    당신이 당신의 논리에 거의 고체 흐름이있는 경우, 적절한 SQL 방식을 구현하는 것은 복잡 할 것입니다. 이 경우 LINQ는 해결책이 될 것입니다.

    당신이 (저장 프로 시저)에 직접 SQL에 로직의 일부를 낮출 수 있다면 당신은 내가 (인덱스를 사용)을 보여 두 번째 쿼리를 실행하고 SQL을 생성 할 수 있습니다와의 실행 계획을 저장할 수 있기 때문에, 그것은 더 나은 것 쿼리 (성능 향상).

  2. ==============================

    2.사용해보십시오

    사용해보십시오

    FROM [TableX]
    ORDER BY [FieldX]
    OFFSET 500 ROWS
    FETCH NEXT 100 ROWS ONLY
    

    메모리에로드하지 않고, (501)로부터 SQL 서버에 600 행 도착. 이 구문은 SQL 서버 2012 사용할 수있게되었음을 참고 만

  3. ==============================

    3.LINQ - 투 - SQL은 OFFSET 절을 생성하는 동안 (아마도 사용하여 에뮬레이션 ROW_NUMBER () OVER () 다른 언급이), SQL에서 페이징을 수행 할 수있는 완전히 다른, 훨씬 더 빠른 방법이있다. 이것은 종종 여기이 블로그 게시물에 설명 된대로이 "방법을 추구"라고합니다.

    LINQ - 투 - SQL은 OFFSET 절을 생성하는 동안 (아마도 사용하여 에뮬레이션 ROW_NUMBER () OVER () 다른 언급이), SQL에서 페이징을 수행 할 수있는 완전히 다른, 훨씬 더 빠른 방법이있다. 이것은 종종 여기이 블로그 게시물에 설명 된대로이 "방법을 추구"라고합니다.

    SELECT TOP 10 first_name, last_name, score
    FROM players
    WHERE (score < @previousScore)
       OR (score = @previousScore AND player_id < @previousPlayerId)
    ORDER BY score DESC, player_id DESC
    

    @previousScore 및 @previousPlayerId 값은 이전 페이지에서 마지막 레코드의 각각의 값입니다. 이것은 당신이 "다음"페이지를 가져 오지 수 있습니다. 방향 BY 순서는 ASC 인 경우, 단순히 대신> 사용합니다.

    위의 방법을 사용하면 즉시 먼저 이전 (40 개) 기록을 인출하지 않고 4 페이지로 이동할 수 없습니다. 그러나 종종, 당신은 지금까지 어쨌든 점프하고 싶지 않아요. 대신, 당신은 당신의 색인에 따라 일정 시간에 데이터를 가져올 수있을 훨씬 빠른 쿼리를 얻을. 또한, 페이지가 "안정적"유지, 아무리 경우 (예를 들어, 1 페이지, 당신은 4 페이지에있는 동안) 기본 데이터가 변경됩니다.

    이 게으른 로딩 더 많은 웹 애플리케이션의 데이터 예를 들어, 페이징을 구현하는 가장 좋은 방법입니다.

    참고가 "방법을 추구"도 키 집합 페이징이라고합니다.

  4. ==============================

    4.LinqToSql 자동으로 당신을 위해 (N1) .Take (N2)로 TSQL 구문 .Skip 변환합니다. 사실, 당신이 Linq에의 할 때마다 "쿼리는"실제로 단지 백그라운드에서 당신을 위해 SQL 쿼리를 만드는 것입니다. 응용 프로그램이 실행되는 동안이를 테스트하려면, 단지 SQL 프로파일 러를 실행합니다.

    LinqToSql 자동으로 당신을 위해 (N1) .Take (N2)로 TSQL 구문 .Skip 변환합니다. 사실, 당신이 Linq에의 할 때마다 "쿼리는"실제로 단지 백그라운드에서 당신을 위해 SQL 쿼리를 만드는 것입니다. 응용 프로그램이 실행되는 동안이를 테스트하려면, 단지 SQL 프로파일 러를 실행합니다.

    스킵은 / 방법론은 내가 읽은 어떤에서 저를 위해 아주 잘 작동하고, 다른 한 걸릴.

    호기심, 당신은 / 테이크를 건너 Linq를보다 더 효율적입니다 믿고, 당신은 자기 호출의 유형을 쿼리?

  5. ==============================

    5.우리는 CTE가 저장 프로 시저 내에서 (우리의 응용 프로그램이 데이터 서버 측의 동적 정렬을 필요로하기 때문에) 동적 SQL에 싸여 사용합니다. 당신이 원한다면 나는 기본 예제를 제공 할 수 있습니다.

    우리는 CTE가 저장 프로 시저 내에서 (우리의 응용 프로그램이 데이터 서버 측의 동적 정렬을 필요로하기 때문에) 동적 SQL에 싸여 사용합니다. 당신이 원한다면 나는 기본 예제를 제공 할 수 있습니다.

    내가 LINQ가 생산하는 T / SQL을 보는 기회가 없었어요. 누군가가 샘플을 게시 할 수 있습니까?

    우리는 보안의 추가 레이어를 필요로 우리는 테이블에 LINQ 또는 연속 액세스를 사용하지 않는 (동적 SQL 구분이 다소 부여).

    이런 식으로 뭔가 트릭을 할해야합니다. 당신은 등의 매개 변수에 대한 파라미터 값을 추가 할 수 있습니다

    exec sp_executesql 'WITH MyCTE AS (
        SELECT TOP (10) ROW_NUMBER () OVER ' + @SortingColumn + ' as RowID, Col1, Col2
        FROM MyTable
        WHERE Col4 = ''Something''
    )
    SELECT *
    FROM MyCTE
    WHERE RowID BETWEEN 10 and 20'
    
  6. ==============================

    6.에서 SQL 서버 2008 :

    에서 SQL 서버 2008 :

    DECLARE @PAGE INTEGER = 2
    DECLARE @TAKE INTEGER = 50
    
    SELECT [t1].*
    FROM (
        SELECT ROW_NUMBER() OVER (ORDER BY [t0].[COLUMNORDER] DESC) AS [ROW_NUMBER], [t0].*
        FROM [dbo].[TABLA] AS [t0]
        WHERE ([t0].[COLUMNS_CONDITIONS] = 1)
        ) AS [t1]
    WHERE [t1].[ROW_NUMBER] BETWEEN ((@PAGE*@TAKE) - (@TAKE-1)) AND (@PAGE*@TAKE)
    ORDER BY [t1].[ROW_NUMBER]
    

    T0에서 모든 기록은 T1에서 해당 페이지에 대응하는 전용들이다

  7. ==============================

    7.당신은 더이 프라하, 단, 성능을 향상시킬 수 있습니다

    당신은 더이 프라하, 단, 성능을 향상시킬 수 있습니다

    From CityEntities c
    Inner Join dbo.MtCity t0 on c.CodCity = t0.CodCity
    Where c.Row Between @p0 + 1 AND @p0 + @p1
    Order By c.Row Asc
    

    이 방법에서를 사용할 경우 더 나은 결과를 줄 것이다 :

    From   dbo.MtCity  t0
       Inner Join  CityEntities c on c.CodCity = t0.CodCity
    

    이유 : 당신이 MtCity에 합류하기 전에 많은 기록을 제거 할 CityEntities 테이블의 경우 클래스를 사용하고 있기 때문에, 그래서 100 % 확신이 성능에 많은 배 증가 ...

    로드리고의 도움에 의해 어쨌든 대답은 정말 도움이됩니다.

    감사

  8. ==============================

    8.당신은 PageIndex를 전달하여이 간단한 방법으로 페이징을 구현할 수 있습니다

    당신은 PageIndex를 전달하여이 간단한 방법으로 페이징을 구현할 수 있습니다

    Declare @PageIndex INT = 1
    Declare  @PageSize INT = 20
    
    Select ROW_NUMBER() OVER ( ORDER BY Products.Name ASC )  AS RowNumber,
        Products.ID,
        Products.Name
    into #Result 
    From Products
    
    SELECT @RecordCount = COUNT(*) FROM #Results 
    
    SELECT * 
    FROM #Results
    WHERE RowNumber
    BETWEEN
        (@PageIndex -1) * @PageSize + 1 
        AND
        (((@PageIndex -1) * @PageSize + 1) + @PageSize) - 1
    
  9. ==============================

    9.2008 년 우리는 건너 뛰기 ()를 사용하지 못할. 가라 ()

    2008 년 우리는 건너 뛰기 ()를 사용하지 못할. 가라 ()

    방법은 다음과 같습니다

    var MinPageRank = (PageNumber - 1) * NumInPage + 1
    var MaxPageRank = PageNumber * NumInPage
    
    var visit = Visita.FromSql($"SELECT * FROM (SELECT [RANK] = ROW_NUMBER() OVER (ORDER BY Hora DESC),* FROM Visita WHERE ) A WHERE A.[RANK] BETWEEN {MinPageRank} AND {MaxPageRank}").ToList();
    
  10. from https://stackoverflow.com/questions/548475/efficient-way-to-implement-paging by cc-by-sa and MIT license