programing

Oracle에 의한 페이징

lastmoon 2023. 4. 2. 11:51
반응형

Oracle에 의한 페이징

저는 오라클에 대해 제가 원하는 만큼 잘 알지 못합니다.25만 장 정도의 레코드가 있는데 한 장당 100장씩 표시하고 싶습니다.현재 데이터 어댑터, 데이터 어댑터 및 데이터 어댑터를 사용하여 데이터 세트에 대한 25만 개의 레코드를 모두 검색하는 하나의 저장 프로시저가 있습니다.저장된 proc의 결과에 따라 fill(데이터셋) 메서드를 입력합니다.파라미터로 전달할 수 있는 정수값으로 "페이지 번호"와 "페이지당 레코드 수"가 있는 경우 해당 섹션만 반환하는 가장 좋은 방법은 무엇입니까?예를 들어, 페이지 번호로는 10, 페이지 수로는 120을 넘긴다면, 선택 문장에서 1880번째에서 1200번째까지가 됩니다. 제 머릿속 계산은 틀릴지도 모릅니다.

에서 이 작업을 하고 있습니다.NET with C#은 중요하지 않다고 생각했기 때문에 SQL 측에서 바로 얻을 수 있다면 저는 괜찮을 것입니다.

업데이트: Brian의 제안을 사용할 수 있었고, 잘 작동하고 있습니다.최적화 작업을 하고 싶은데, 페이지가 1분이 아니라 4~5초 안에 뜨기 때문에 페이징 컨트롤이 새로운 저장 프로와 매우 잘 통합될 수 있었습니다.

Frans Bouma의 블로그에서 본 내용입니다.

SELECT * FROM
(
    SELECT a.*, rownum r__
    FROM
    (
        SELECT * FROM ORDERS WHERE CustomerID LIKE 'A%'
        ORDER BY OrderDate DESC, ShippingDate DESC
    ) a
    WHERE rownum < ((pageNumber * pageSize) + 1 )
)
WHERE r__ >= (((pageNumber-1) * pageSize) + 1)

페이지 매김과 매우 유용한 분석 기능에 대해 톰에게 물어보세요.

이 페이지에서 발췌한 내용은 다음과 같습니다.

select * from (
    select /*+ first_rows(25) */
     object_id,object_name,
     row_number() over
    (order by object_id) rn
    from all_objects
)
where rn between :n and :m
order by rn;

완성도를 높이기 위해 보다 현대적인 솔루션을 찾고 있는 사용자를 위해 Oracle 12c에는 보다 나은 페이징과 톱 핸들링 등 몇 가지 새로운 기능이 있습니다.

페이징

페이징은 다음과 같습니다.

SELECT *
FROM user
ORDER BY first_name
OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY;

상위 N개 레코드

상위 레코드를 얻는 방법은 다음과 같습니다.

SELECT *
FROM user
ORDER BY first_name
FETCH FIRST 5 ROWS ONLY

위의 두 쿼리 예제 모두ORDER BY절을 참조하십시오.새로운 명령어는 이러한 내용을 고려하여 정렬된 데이터에서 실행됩니다.

적합한 Oracle 참조 페이지를 찾을 수 없습니다.FETCH또는OFFSET이 페이지에는 이러한 신기능의 개요가 기재되어 있습니다.

성능

@wweicker가 다음 코멘트에서 지적한 바와 같이 12c의 새로운 구문에서는 퍼포먼스가 문제입니다.이후 Oracle이 개선했는지 테스트할 18c 복사본이 없었습니다.

흥미롭게도 새로운 메서드에 대해 처음 테이블에서 쿼리를 실행했을 때(1억1300만 행 이상) 실제 결과가 약간 더 빨리 반환되었습니다.

  • 새로운 방법: 0.013초
  • 이전 방식: 0.107초

단, @wweicker가 언급했듯이 새로운 메서드에 대한 설명 계획은 훨씬 더 나빠 보입니다.

  • 새로운 방법 비용: 300,110
  • 이전 방식 비용: 30

새로운 구문으로 인해 내 컬럼에 있는 인덱스의 전체 스캔이 발생하였고, 전체 비용이 발생하였습니다.인덱스화되지 않은 데이터를 제한하면 상황이 훨씬 악화될 수 있습니다.

이전 데이터 세트에 색인화되지 않은 단일 열을 포함하는 경우를 살펴보겠습니다.

  • 새로운 방식 시간/비용: 189.55초/998,908
  • 이전 방식 시간/비용: 1.973초/256

개요: Oracle이 이 처리를 개선할 때까지 주의하여 사용하십시오.작업할 인덱스가 있으면 새 방법을 사용할 수 있습니다.

곧 18c를 가지고 놀 수 있고 업데이트 할 수 있기를 바랍니다.

답변과 코멘트를 요약하고 싶을 뿐입니다.페이지 매기기에는 여러 가지 방법이 있습니다.

oracle 12c 이전에는 OFFSET/FETCH 기능이 없었기 때문에 @jasonk가 제안하는 화이트 페이퍼를 참조하십시오.다양한 방법에 대해 장점과 단점을 자세히 설명한 가장 완벽한 기사입니다.복사 붙여넣기에는 상당한 시간이 걸리기 때문에 하지 않겠습니다.

또한 Oracle 및 기타 데이터베이스 페이지 지정과 관련된 몇 가지 일반적인 경고를 설명하는 jooq 크리에이터의 좋은 글도 있습니다.jooq의 블로그 포스트

희소식입니다. Oracle 12c 이후 새로운 OFFSET/FETCH 기능이 추가되었습니다.Oracle Magazine 12c 신기능"상위 N개 쿼리 및 페이지 번호 지정"을 참조하십시오.

다음 명령문을 발행하여 Oracle 버전을 확인할 수 있습니다.

SELECT * FROM V$VERSION

다음을 시도해 보십시오.

SELECT *
FROM
  (SELECT FIELDA,
    FIELDB,
    FIELDC,
    ROW_NUMBER() OVER (ORDER BY FIELDC) R
  FROM TABLE_NAME
  WHERE FIELDA = 10
  )
WHERE R >= 10
AND R   <= 15;

[tecnicume] 경유

프로젝트에서는 Oracle 12c와 java를 사용했습니다.페이징 코드는 다음과 같습니다.

 public public List<Map<String, Object>> getAllProductOfferWithPagination(int pageNo, int pageElementSize, Long productOfferId, String productOfferName) {
    try {

        if(pageNo==1){
            //do nothing
        } else{
            pageNo=(pageNo-1)*pageElementSize+1;
        }
        System.out.println("algo pageNo: " + pageNo +"  pageElementSize: "+ pageElementSize+"  productOfferId: "+ productOfferId+"  productOfferName: "+ productOfferName);

        String sql = "SELECT * FROM ( SELECT * FROM product_offer po WHERE po.deleted=0 AND (po.product_offer_id=? OR po.product_offer_name LIKE ? )" +
             " ORDER BY po.PRODUCT_OFFER_ID asc) foo OFFSET ? ROWS FETCH NEXT ? ROWS ONLY ";

       return jdbcTemplate.queryForList(sql,new Object[] {productOfferId,"%"+productOfferName+"%",pageNo-1, pageElementSize});

    } catch (Exception e) {
        System.out.println(e);
        e.printStackTrace();
        return null;
    }
    In SomeServiceClass 
    using npoco
    
    public async Task<List<SomeModel>> SomeServiceMethod(int pageIndex, int pageSize)
    
                    int lowerLimit;
                    int higherLimit;
    //This would help limit the result to 300 max. If the PageSize is stated as 290
    //we get the 1st to 289th result. If page size is 1845.
    //It returns 1845 - 299 = 1546. 1546th element to 1844th element
    
                    if((pageSize) < 300)
                    {
                        lowerLimit = 1;
                        higherLimit = pageSize;
                    }
                    else
                    {
                        int subtract = 300 - 1;
                        lowerLimit = pageSize - subtract;
                        higherLimit = pageSize;
                    }
    
    //Using Brian Schmitt script

    List<SomeModel> someVariableName = db.Query<SomeModel>(SELECT * FROM
    (
        SELECT a.*, rownum r__
        FROM
        (
            SELECT * FROM ORDERS WHERE CustomerID LIKE 'A%'
            ORDER BY OrderDate DESC, ShippingDate DESC
        ) a
        WHERE rownum < (@0)
    )
    WHERE r__ >= (@1), higherlimit, lowerlimit).ToList();
    
    
    
    In SomeControllerClass

    [HttpGet]
    [Route("SomeControllerMethod")]
    public async Task<SomeResponseModel> SomeControllerMethod(int pageIndex, int pageSize)
    
    SomeServiceClass ssc = new SomeServiceClass();
    SomeResponseModel srm = new SomeResponseModel();
    
    List<SomeModel> resp = await ssc.SomeServiceMethod(pageIndex, pageSize);
    
    //Paging on API level, solution is from CSharpCorner. This would return a //max of 20 elements per page. 
    //So if you have a result of 300. It would be divided into 15 pages.
    //20 results per page. 

                    int totalRecords = resp.Count();
    
    
                    const int maxPageSize = 20;
                    pageSize = (pageSize > maxPageSize) ? maxPageSize : pageSize;
                    int pageNum = pageIndex;
                    int recordToTake = totalRecords - (pageNum - 1) * pageSize;
                    int CurrentPage = pageNum;
                    int TotalPages = (int)Math.Ceiling(totalRecords / (double)pageSize);
                    var previousPage = CurrentPage > 1 ? "Yes" : "No";
                    var nextPage = CurrentPage < TotalPages ? "Yes" : "No";
                    List<SomeModel> filteredResult = resp.Skip((CurrentPage - 1) * pageSize).Take(pageSize).ToList();
    
    
                    
                    srm.records = totalRecords;
                    srm.previousPage = previousPage;
                    srm.currentPage = $"Page: {CurrentPage} / {TotalPages}";
                    srm.nextPage = nextPage;
                    srm.totalPages = TotalPages;
                    srm.someIEnumerableProperty = filteredResult;
    
    return srm;


//How to use endpoint
//http://localhost:somePort/someControllerClass/SomeControllerMethod?pageIndex={pageIndex}&pageSize={pageSize}

//pageIndex will take value 1 to 15 since we have a max of 300 and 20 results per page.
//pageSize will be used to determine our higherlimit

언급URL : https://stackoverflow.com/questions/241622/paging-with-oracle

반응형