programing

효율적인 페이징 구현 방법

muds 2023. 5. 6. 16:45
반응형

효율적인 페이징 구현 방법

LINQ를 ?Skip()그리고.Take()호출 방법 또는 SQL 쿼리를 사용하여 자체 호출을 구현할 수 있습니까?

어떤 것이 가장 효율적입니까?내가 왜 다른 것보다 하나를 선택하겠습니까?

SQL Server 2008, ASP를 사용하고 있습니다.NET MVC 및 LINQ.

의문에 , 이 당의의심대답노있주습고, 만당이실면다한행을 한다면,skip(n).take(m) 2005서버로 사용) 는 linq(SQL 2005/2008을 사용합니다.Select ROW_NUMBER() Over ...SQL 엔진에서 직접 페이징을 사용하는 문입니다.

저는 예를들어, 다같은과음 DB다이있습라는 DB .mtcity그리고 다음과 같은 질의를 작성했습니다(엔티티에 대한 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]

윈도우 데이터 액세스입니다(매우 쿨하지만, btwz는 처음부터 데이터를 반환하고 조건이 충족되는 한 테이블에 액세스합니다).이는 다음과 매우 유사합니다.

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에서 쿼리의 실행 계획을 생성하고(성능 향상) 저장할 수 있기 때문에 훨씬 더 좋습니다.

사용해 보십시오.

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

메모리에 로드하지 않고 SQL 서버에서 501 ~ 600까지의 행을 가져옵니다.이 구문은 SQL Server 2012에서만 사용할 수 있습니다.

은 LINQ-to-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값은 이전 페이지의 마지막 레코드의 각 값입니다.이렇게 하면 "다음" 페이지를 가져올 수 있습니다.에 약에만.ORDER BY은 방은향입니다.ASC 순한사용을 사용합니다.>대신.

위의 방법을 사용하면 이전 40개의 레코드를 먼저 가져오지 않고는 즉시 4페이지로 이동할 수 없습니다.하지만 종종, 여러분은 어쨌든 그렇게 멀리 뛰고 싶지 않을 것입니다.대신 인덱싱에 따라 데이터를 일정한 시간 내에 가져올 수 있는 훨씬 빠른 쿼리를 얻을 수 있습니다.또한 기본 데이터가 변경되더라도 페이지는 "안정적"으로 유지됩니다(예: 사용자가 4페이지에 있는 동안 1페이지에서).

예를 들어 웹 응용 프로그램에서 더 많은 데이터를 로드하는 것이 번거로울 때 페이징을 구현하는 가장 좋은 방법입니다.

"검색 방법"은 키셋 페이징이라고도 합니다.

LinkqToSql은 .Skip(N1)을 자동으로 변환합니다.(N2) TSQL 구문을 살펴봅니다.실제로 Linq에서 수행하는 모든 "쿼리"는 백그라운드에서 사용자를 위한 SQL 쿼리를 만드는 것입니다.이를 테스트하려면 응용 프로그램이 실행되는 동안 SQL Profiler를 실행하면 됩니다.

스킵/테이크 방법론은 제가 읽은 바로는 저와 다른 사람들에게 매우 잘 작동했습니다.

호기심에서, 당신은 어떤 종류의 자체 페이징 쿼리를 가지고 있습니까? 당신은 Linq의 건너뛰기/테이크보다 더 효율적이라고 생각합니까?

저장 프로시저 내에서 동적 SQL로 포장된 CTE를 사용합니다(데이터 서버 측의 동적 정렬이 필요하기 때문에).원하신다면 기본적인 예를 제시해 드릴 수 있습니다.

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'

SQL Server 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]

int0은 모든 레코드입니다. int1은 해당 페이지에 해당하는 레코드만 있습니다.

제가 제시하는 접근 방식은 SQL 서버가 달성할 수 있는 가장 빠른 페이지입니다.저는 이것을 5백만 개의 레코드에서 테스트했습니다.이 접근 방식은 SQL Server에서 제공하는 "OFFset 10 ROWS FETH NEXT 10 ROWS 전용"보다 훨씬 더 우수합니다.

-- The below given code computes the page numbers and the max row of previous page
-- Replace <<>> with the correct table data.
-- Eg. <<IdentityColumn of Table>> can be EmployeeId and <<Table>> will be dbo.Employees

DECLARE @PageNumber int=1; --1st/2nd/nth page. In stored proc take this as input param.
DECLARE @NoOfRecordsPerPage int=1000;

 DECLARE @PageDetails TABLE
       (
        <<IdentityColumn of Table>> int,
        rownum int,
        [PageNumber] int
       )           
       INSERT INTO @PageDetails values(0, 0, 0)
       ;WITH CTE AS
       (
       SELECT <<IdentityColumn of Table>>, ROW_NUMBER() OVER(ORDER BY <<IdentityColumn of Table>>) rownum FROM <<Table>>
       )
       Insert into @PageDetails 
       SELECT <<IdentityColumn of Table>>, CTE.rownum, ROW_NUMBER() OVER (ORDER BY rownum) as [PageNumber] FROM CTE WHERE CTE.rownum%@NoOfRecordsPerPage=0


--SELECT * FROM @PageDetails 

-- Actual pagination
SELECT TOP (@NoOfRecordsPerPage)
FROM <<Table>> AS <<Table>>
WHERE <<IdentityColumn of Table>> > (SELECT <<IdentityColumn of Table>> FROM 
@PageDetails WHERE PageNumber=@PageNumber)
ORDER BY <<Identity Column of Table>>

성능을 더욱 향상시킬 수 있습니다. 이것을 확인하십시오.

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을 사용하면 더 나은 결과를 얻을 수 있습니다.

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

이유: MtCity에 가입하기 전에 많은 레코드를 제거하는 CityEntities 테이블의 where 클래스를 사용하고 있기 때문에 성능이 여러 배로 향상될 것이라고 100% 확신합니다.

어쨌든 로드리고엘프의 답변은 정말 도움이 됩니다.

감사해요.

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

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();

언급URL : https://stackoverflow.com/questions/548475/efficient-way-to-implement-paging

반응형