programing

(오라클)페이지화 쿼리를 사용할 때 총 결과 수를 가져오는 방법은 무엇입니까?

powerit 2023. 6. 17. 09:46
반응형

(오라클)페이지화 쿼리를 사용할 때 총 결과 수를 가져오는 방법은 무엇입니까?

저는 Oracle 10g 및 다음 패러다임을 사용하여 15개의 결과 페이지를 시간으로 얻습니다(사용자가 검색 결과의 2페이지를 볼 때 16-30개의 기록을 볼 수 있습니다).

select * 
  from 
( select rownum rnum, a.*
    from (my_query) a
   where rownum <= 30 )
where rnum > 15;

지금은 별도의 SQL 문을 실행하여 my_query에 대한 총 결과 수를 얻기 위해 "select count"를 "my_query"에 대해 수행해야 합니다(사용자에게 보여주고 총 페이지 수 등을 파악하는 데 사용할 수 있도록).

두 번째 쿼리를 통해 이 작업을 수행하지 않고 총 결과 수를 얻을 수 있는 방법이 있습니까? 즉, 위 쿼리에서 결과를 가져오는 방법이 있습니까?"max(rownum)"를 추가하려고 했지만 작동하지 않는 것 같습니다(그룹에서 키워드 rownum을 by로 사용하는 것을 싫어하는 것으로 보이는 오류 [ORA-01747]).

별도의 SQL 문에서 이를 수행하는 것보다 원래 쿼리에서 이를 가져오려는 이유는 "my_query"가 값비싼 쿼리이기 때문에 두 번 실행하지 않는 것이 낫다는 것입니다(한 번 카운트를 얻기 위해).한 번은 데이터 페이지를 가져올 필요가 없지만, 단일 쿼리 내에서 결과 수를 얻기 위한 솔루션(동시에 필요한 데이터 페이지를 얻을 수 있음)은 가능하면 추가 오버헤드가 발생하지 않도록 해야 합니다.조언 부탁드립니다.

이것이 바로 제가 그룹에서 ROWNUM을 가지고 있는 것을 좋아하지 않는다고 믿기 때문에 제가 ORA-01747 오류를 받으려고 하는 것입니다.참고로 max(ROWNUM)를 사용하지 않고 다른 솔루션이 있다면 그것도 완벽하게 좋습니다.이 해결책은 무엇이 효과가 있을지에 대한 저의 첫 번째 생각이었습니다.

 SELECT * FROM (SELECT r.*, ROWNUM RNUM, max(ROWNUM)
 FROM (SELECT t0.ABC_SEQ_ID AS c0, t0.FIRST_NAME, t0.LAST_NAME, t1.SCORE
 FROM ABC t0, XYZ t1
 WHERE (t0.XYZ_ID = 751) AND 
 t0.XYZ_ID = t1.XYZ_ID 
 ORDER BY t0.RANK ASC) r WHERE ROWNUM <= 30 GROUP BY r.*, ROWNUM) WHERE RNUM > 15

EDIT -------- 참고, 첫 번째 의견을 바탕으로 작동하는 것으로 보이는 다음을 시도했습니다.하지만 다른 솔루션에 비해 성능이 얼마나 우수한지는 잘 모르겠습니다(제 요구 사항을 충족하지만 최고의 성능을 발휘하는 솔루션을 찾고 있습니다).예를 들어, 이것을 실행하면 16초가 걸립니다.COUNT(*) OVER() () RESULT_COUNT를 꺼내면 7초밖에 걸리지 않습니다.

    SELECT * FROM (SELECT r.*, ROWNUM RNUM, ) 
    FROM (SELECT COUNT(*) OVER () RESULT_COUNT, 
          t0.ABC_SEQ_ID AS c0, t0.FIRST_NAME, t1.SCORE 
    FROM ABC t0, XYZ t1 
    WHERE (t0.XYZ_ID = 751) AND t0.XYZ_ID = t1.XYZ_ID 
    ORDER BY t0.RANK ASC) r WHERE ROWNUM <= 30) WHERE RNUM > 1

설명 계획은 SORT(SORDER BY STOP Key)에서 WINDOW(SORT)로 변경됩니다.

이전:

SELECT STATEMENT () 
 COUNT (STOPKEY)    
  VIEW ()   
   SORT (ORDER BY STOPKEY)  
    NESTED LOOPS () 
     TABLE ACCESS (BY INDEX ROWID)  XYZ
      INDEX (UNIQUE SCAN)   XYZ_ID
     TABLE ACCESS (FULL)    ABC

이후:

SELECT STATEMENT () 
 COUNT (STOPKEY)    
  VIEW ()   
   WINDOW (SORT)    
    NESTED LOOPS () 
     TABLE ACCESS (BY INDEX ROWID)  XYZ
      INDEX (UNIQUE SCAN)   XYZ_ID
     TABLE ACCESS (FULL)    ABC

"단일" 쿼리에서 원하는 모든 정보를 얻으려면 쿼리를 이와 같은 것으로 수정해야 한다고 생각합니다.

SELECT *
FROM (SELECT r.*, ROWNUM RNUM, COUNT(*) OVER () RESULT_COUNT 
      FROM (SELECT t0.ABC_SEQ_ID AS c0, t0.FIRST_NAME, t1.SCORE
            FROM ABC t0, XYZ t1
            WHERE (t0.XYZ_ID = 751) 
            AND t0.XYZ_ID = t1.XYZ_ID 
            ORDER BY t0.RANK ASC) R)
WHERE RNUM between 1 and 15 

는 그이는유 때문입니다.COUNT(*) OVER()윈도우 함수는 다음에 평가됩니다.WHERE 총 해당 수를 절입니다.ROWNUM <= 30조건.

만약 당신이 이 쿼리의 성능을 받아들일 수 없거나 두 개의 별도 쿼리를 실행할 수 없다면, 당신은 좌절감에 의해 제안된 것과 같은 해결책을 생각해야 할 것입니다.레코드 수 캐싱에 대한 의견을 FormsDesigner와 함께 제공합니다.

데이터베이스를 정기적으로 사용하는 경우 SQL Cookbook을 구입하는 것이 좋습니다.그것은 많은 유용한 조언들이 있는 예외적인 책입니다.

아니요, 쿼리를 두 번 실행하거나, 쿼리를 한 번 실행하고 모든 행을 가져와 카운트한 후 표시하지 않으면 쿼리를 실행할 수 없습니다.특히 쿼리가 비싸거나 많은 행을 반환할 가능성이 있는 경우에는 둘 다 바람직하지 않습니다.

Oracle의 Application Express(Apex) 도구는 다음과 같은 페이지 옵션을 제공합니다.

  1. 가장 효율적인 방법은 "더 많은" 행이 있는지 여부를 나타냅니다.이를 위해 현재 페이지 최대치(예: 16-30행을 표시하는 페이지의 경우 31행)보다 한 행만 더 가져옵니다.
  2. 또는 "67개 중 16-30개" 또는 "200개 이상 중 16-30개"를 표시할 수 있는 제한된 카운트를 표시할 수 있습니다.즉, 최대 201개의 행(이 예에서는)을 가져옵니다.이것은 옵션 1만큼 효율적이지 않지만 옵션 3보다 효율적입니다.
  3. 또는 실제로 "13,945 중 16-30"을 보여줄 수 있습니다.이를 위해 Apex는 13,945개를 모두 가져와야 하지만 15-30개 행을 제외한 모든 행을 버려야 합니다.이것이 가장 느리고 효율성이 떨어지는 방법입니다.

옵션 3에 대한 유사 PL/SQL(사용자의 선호도)

l_total := 15;
for r in 
  ( select * 
      from 
    ( select rownum rnum, a.*
        from (my_query) a
    )
    where rnum > 15
  )
loop
   l_total := l_total+1;
   if runum <= 30 then
      print_it;
   end if;
end loop;
show_page_info (15, 30, l_total);

제안일 뿐입니다.

Google의 "약 13,000,000개 결과 중 1-10개" 접근 방식을 고려할 수 있습니다. - COUNT(*)를 원래 쿼리에 대한 빠른 샘플로 실행합니다.난 여기에 기껏해야 한 명이 있을 거라고 추측했어요.XYZ당연한 일이지만ABC:

SELECT *
FROM (SELECT r.*, ROWNUM RNUM, 
      (SELECT COUNT(*) * 100
       FROM ABC SAMPLE(1) t0
       WHERE (t0.XYZ_ID = 751)
      ) RESULT_COUNT 
  FROM (SELECT t0.ABC_SEQ_ID AS c0, t0.FIRST_NAME, t1.SCORE
        FROM ABC t0, XYZ t1
        WHERE (t0.XYZ_ID = 751) 
        AND t0.XYZ_ID = t1.XYZ_ID 
        ORDER BY t0.RANK ASC) R)
WHERE RNUM between 1 and 15 

분명히 샘플은 상당히 부정확하고 가변적일 것이기 때문에 이것이 적절한지 여부는 요구 사항에 따라 달라집니다.

이것이 효과가 있습니까?

select * 
  from 
( select rownum rnum, a.*, b.total
    from (my_query) a,   (select count(*) over () total from my_query) b
   where rownum <= 30 )
where rnum > 15;

또 다른 솔루션은 각 값에 대한 카운트를 관리하는 구체화된 뷰를 생성하는 것입니다.ABC.XYZ_ID이렇게 하면 테이블에 행을 삽입/업데이트/삭제하는 프로세스에 카운트를 할당해야 하는 부담이 생깁니다.

WITH
base AS
(
    SELECT ROWNUM RNUM, A.*
    FROM (SELECT * FROM some_table WHERE some_condition) A
)
SELECT FLOOR(((SELECT COUNT(*) FROM base) / 15) + 1) TOTAL_PAGES_TO_FETCH, 
       ((ROWNUM - MOD(ROWNUM, 15)) / 15) + 1 PAGE_TO_FETCH,
       B.*
FROM base B

이 쿼리는 가져올 페이지 그룹 수를 계산하고 데이터를 하나의 쿼리로 가져옵니다.

결과 집합에서 한 번에 15개 행을 처리합니다.마지막 행 집합은 15보다 짧을 수 있습니다.

Evil Teach의 답변을 기반으로 구축하기:

WITH
base AS
(
    SELECT (ROWNUM - 1) RNUM, A.*
    FROM (SELECT * FROM some_table WHERE some_condition) A
)
SELECT V.* FROM (
  SELECT FLOOR(((SELECT COUNT(*) FROM base) / 15) + 1) TOTAL_PAGES_TO_FETCH, 
         ((RNUM - MOD(RNUM, 15)) / 15) + 1 PAGE_TO_FETCH,
         B.*
  FROM base B
) V
WHERE V.PAGE_TO_FETCH = xx

여기서 XX는 당신이 원하는 페이지입니다.

위 솔루션에는 첫 페이지가 PAGE_SIZE - 1 결과를 반환하게 만든 원래 코드에 대한 작은 버그 수정이 포함되어 있습니다.

두 번째 쿼리를 통해 이 작업을 수행하지 않고 총 결과 수를 얻을 수 있는 방법이 있습니까? 즉, 위 쿼리에서 결과를 가져오는 방법이 있습니까?

Oracle 12c의 경우 다음과 같이 작동합니다.

-- use count analytic function
select a.*, count(*) over() as total_nb_results from mytable a
offset 10 rows fetch next 10 rows only 

요청에 의해 반환된 총 레코드 수("오프셋/페치" 절이 없는 경우)와 함께 10번째 레코드에서 시작하여 각각 10개 행의 배치를 반환합니다.

또한 분석을 완벽하게 사용할 수 있습니다.countOracle 10g에서도 작동합니다.

언급URL : https://stackoverflow.com/questions/2905199/oracle-how-get-total-number-of-results-when-using-a-pagination-query

반응형