문제

DB에서 나오는 데이터를 통해 페이징 할 때는 페이지 점프 컨트롤을 렌더링하는 페이지 수를 알아야합니다.

현재 나는 한 번 쿼리를 두 번 실행하여 count() 총 결과를 결정하고 제한이 적용된 두 번째 시간은 현재 페이지에 필요한 결과 만 되 찾을 수 있습니다.

이것은 비효율적 인 것 같습니다. 이전에 몇 개의 결과가 반환되었는지 결정하는 더 좋은 방법이 있습니까? LIMIT 적용 되었습니까?

PHP와 Postgres를 사용하고 있습니다.

도움이 되었습니까?

해결책

순수한 SQL

2008 년부터 상황이 바뀌 었습니다 창 함수 한 쿼리를 전체 카운트와 제한된 결과를 얻으려면. (소개 2009 년 PostgreSQL 8.4).

SELECT foo
     , count(*) OVER() AS full_count
FROM   bar
WHERE  <some condition>
ORDER  BY <some col>
LIMIT  <pagesize>
OFFSET <offset>

이것은 총 수가없는 것보다 훨씬 비쌀 수 있습니다. 모든 행을 계산해야하며, 일치하는 인덱스에서 상단 행 만 가져갈 수있는 바로 가기는 더 이상 도움이되지 않을 수 있습니다.
작은 테이블이나 그다지 중요하지 않습니다 full_count <= OFFSET + LIMIT. 실질적으로 더 큰 문제 full_count.

코너 케이스: 언제 OFFSET 적어도 기본 쿼리의 행 수만큼이나 좋습니다. 줄 없음 반환됩니다. 그래서 당신은 또한 아니요 full_count. 가능한 대안 :

고려하다 사건의 연속:

  1. WHERE 절 (및 JOIN 조건이지만 여기에는 없음)베이스 테이블에서 자격있는 행을 필터링합니다.

    (GROUP BY 그리고 집계 기능은 여기에 갈 것입니다.)

  2. 윈도우 함수는 모든 적격 행을 고려하여 적용됩니다 ( OVER 조항 및 함수의 프레임 사양). 단순한 count(*) OVER() 모든 행을 기반으로합니다.

  3. ORDER BY

    (DISTINCT 또는 DISTINCT ON 여기에 갈 것입니다.)

  4. LIMIT / OFFSET 반환 할 행을 선택하기 위해 확립 된 순서에 따라 적용됩니다.

LIMIT / OFFSET 테이블에서 점점 더 많은 행으로 인해 점점 비효율적입니다. 더 나은 성능이 필요한 경우 대체 접근 방식을 고려하십시오.

최종 수를 얻기위한 대안

영향을받는 행의 수를 얻는 데 완전히 다른 접근법이 있습니다 (~ 아니다 이전의 전체 수 OFFSET & LIMIT 적용). Postgres는 마지막 SQL 명령의 영향을받는 행 수를 내부 부기를 가지고 있습니다. 일부 클라이언트는 PSQL과 같이 해당 정보에 액세스하거나 행을 카운트 할 수 있습니다.

예를 들어, 영향을받는 행의 수를 검색 할 수 있습니다. PLPGSQL SQL 명령을 실행 한 직후 :

GET DIAGNOSTICS integer_var = ROW_COUNT;

매뉴얼의 세부 사항.

또는 사용할 수 있습니다 pg_num_rows 안에 PHP. 또는 다른 고객의 유사한 기능.

관련된:

다른 팁

내가 설명하는대로 내 블로그에서, MySQL에는 부르는 기능이 있습니다 sql_calc_found_rows. 이렇게하면 쿼리를 두 번 수행 할 필요가 없지만 한계 조항이 일찍 중지 할 수 있었음에도 불구하고 여전히 쿼리를 수행해야합니다.

내가 아는 한, postgresql에 대한 유사한 기능은 없습니다. 페이지 매김을 할 때 조심해야 할 한 가지는 (한계가 IMHO를 사용하는 가장 일반적인 것) : "오프셋 1000 리미트 10"을 수행하는 것은 DB가 가져와야한다는 것을 의미합니다. 적어도 1010 행은 10 만 제공하더라도 10을 제공하더라도 이전 행 (이 경우 1000 번째)에 대해 주문한 행의 값을 기억하고 다음과 같이 쿼리를 다시 작성하는 것입니다. . 여기서 order_row> value_of_1000_th 리미트 10 ". 장점은 "Order_row"가 아마도 인덱싱된다는 것입니다 (그렇지 않은 경우 문제가 발생합니다). 단점은 페이지보기 사이에 새로운 요소가 추가되면 동기화가 약간 떨어질 수 있다는 점입니다 (그러나 다시 방문자는 관찰 할 수 없으며 큰 성능 이득이 될 수 있습니다).

매번 Count () 쿼리를 실행하지 않음으로써 성능 페널티를 완화 할 수 있습니다. 쿼리가 다시 실행되기 5 분 전에 페이지 수를 캐시합니다. 많은 수의 인서트를 보지 않는 한, 그것은 잘 작동해야합니다.

Postgres는 이미 일정량의 캐싱을 수행하기 때문에 이러한 유형의 방법은 비효율적이지 않습니다. 실행 시간이 두 배가되는 것은 아닙니다. 우리는 DB 층에 타이머를 내장하여 증거를 보았습니다.

페이징 목적으로 알아야 할 때 전체 쿼리를 한 번 실행하고 서버 측 캐시로 디스크에 데이터를 작성한 다음 페이징 메커니즘을 통해이를 공급하는 것이 좋습니다.

사용자에게 데이터를 제공할지 여부를 결정하기 위해 카운트 쿼리를 실행하는 경우 (예 :> X 레코드가있는 경우 오류를 돌려 주면) Count 접근 방식을 고수해야합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top