(오라클)페이지화 쿼리를 사용할 때 총 결과 수를 가져오는 방법은 무엇입니까?
저는 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) 도구는 다음과 같은 페이지 옵션을 제공합니다.
- 가장 효율적인 방법은 "더 많은" 행이 있는지 여부를 나타냅니다.이를 위해 현재 페이지 최대치(예: 16-30행을 표시하는 페이지의 경우 31행)보다 한 행만 더 가져옵니다.
- 또는 "67개 중 16-30개" 또는 "200개 이상 중 16-30개"를 표시할 수 있는 제한된 카운트를 표시할 수 있습니다.즉, 최대 201개의 행(이 예에서는)을 가져옵니다.이것은 옵션 1만큼 효율적이지 않지만 옵션 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개 행의 배치를 반환합니다.
또한 분석을 완벽하게 사용할 수 있습니다.count
Oracle 10g에서도 작동합니다.
언급URL : https://stackoverflow.com/questions/2905199/oracle-how-get-total-number-of-results-when-using-a-pagination-query
'programing' 카테고리의 다른 글
파이썬에서 두 번 빼기 (0) | 2023.06.17 |
---|---|
32비트 또는 64비트에 따라 데이터 유형 또는 구조의 크기는 누가 결정합니까? (0) | 2023.06.17 |
터미널 창의 크기 가져오기(행/열) (0) | 2023.06.17 |
VBA의 하위 문자열 (0) | 2023.06.17 |
Vuex - 5초마다 대용량 데이터 청크 폴링 시 메모리 누수/JS 힙 크기 (0) | 2023.06.17 |