MySQL 데이터-페이징을 구현하는 가장 좋은 방법은 무엇입니까?


209

내 iPhone 앱은 PHP 웹 서비스에 연결하여 MySQL 데이터베이스에서 데이터를 검색합니다. 요청은 500 개의 결과를 반환 할 수 있습니다.

페이징을 구현하고 한 번에 20 개의 항목을 검색하는 가장 좋은 방법은 무엇입니까?

데이터베이스에서 처음 20 개의 광고를 수신한다고 가정 해 보겠습니다. 이제 다음 20 개의 광고를 요청하려면 어떻게해야합니까?

답변:


309

MySQL 문서에서 :

LIMIT 절을 사용하여 SELECT 문에 의해 리턴되는 행 수를 제한 할 수 있습니다. LIMIT는 하나 또는 두 개의 숫자 인수를 취하는데, 둘 다 음이 아닌 정수 상수 여야합니다 (준비된 명령문을 사용할 때 제외).

두 개의 인수를 사용하면 첫 번째 인수는 반환 할 첫 번째 행의 오프셋을 지정하고 두 번째 인수는 반환 할 최대 행 수를 지정합니다. 초기 행의 오프셋은 0 (1 아님)입니다.

SELECT * FROM tbl LIMIT 5,10;  # Retrieve rows 6-15

특정 오프셋에서 결과 집합의 끝까지 모든 행을 검색하려면 두 번째 매개 변수에 큰 숫자를 사용할 수 있습니다. 이 명령문은 96 번째 행에서 마지막 행까지의 모든 행을 검색합니다.

SELECT * FROM tbl LIMIT 95,18446744073709551615;

하나의 인수로 값은 결과 세트의 시작 부분에서 리턴 할 행 수를 지정합니다.

SELECT * FROM tbl LIMIT 5;     # Retrieve first 5 rows

즉, LIMIT row_count는 LIMIT 0, row_count와 같습니다.


107
페이징에 LIMIT를 사용할 때 ORDER BY도 지정해야합니다.
Mark Byers

10
@shylent : 문서를 인용하는 데 아무런 문제가 없지만 문서를 복사하고 원본 소스에 대한 링크를 제공했다고 언급해야한다는 데 동의합니다. 또한 설명서에 ORDER BY없이 LIMIT를 사용하는 예제가 포함되어 있다는 사실에 놀랐습니다. ORDER BY가 없으면 주문이 통화간에 동일하다는 보장이 없습니다.
Mark Byers

13
어쨌든 큰 결과 집합을 페이지 매김 할 때 (그리고 페이지 매김이 큰 결과 집합을 작은 덩어리로 나누는 것입니까?),을 수행하면 limit X, Y본질적으로 일어나는 일은 X + Y 행이 검색되고 처음부터 X 행이 삭제되고 왼쪽이 반환됩니다. 반복 : limit X, YX + Y 행을 스캔합니다.
shylent

7
나는 당신의 LIMIT 95, 천팔백사십사경육천칠백사십사조칠백삼십칠억구백오십오만천육백열다섯 생각처럼하지 않습니다 .. 살펴 OFFSET;-)
CharlesLeaf

5
큰 데이터로 작업 할 때는 비효율적입니다. 특정 장면 에 적합한 다양한 방법은 codular.com/implementing-pagination 을 확인하십시오 .
Amit

125

500 레코드의 경우 효율성은 문제가되지 않지만 수백만 개의 레코드가있는 경우 WHERE 절을 사용하여 다음 페이지를 선택하는 것이 유리할 수 있습니다.

SELECT *
FROM yourtable
WHERE id > 234374
ORDER BY id
LIMIT 20

여기의 "234374"는 이전 페이지에서 본 마지막 레코드의 ID입니다.

그러면 id의 인덱스를 사용하여 첫 번째 레코드를 찾을 수 있습니다. 사용 LIMIT offset, 20하면 페이지 끝까지 갈수록 느리고 느려질 수 있습니다. 내가 말했듯이 200 개의 레코드 만 있으면 문제가되지 않지만 더 큰 결과 집합으로 차이를 만들 수 있습니다.

이 방법의 또 다른 장점은 통화간에 데이터가 변경되면 레코드를 놓치지 않거나 반복되는 레코드를 얻지 못한다는 것입니다. 행을 추가하거나 제거한다는 것은 행이 변경된 후 모든 행의 오프셋을 의미하기 때문입니다. 귀하의 경우에는 중요하지 않을 것입니다-귀하의 광고 풀이 너무 자주 바뀌지 않으며 같은 광고를 두 번 연속해서 얻는 지 아무도 알지 못할 것입니다. 그러나 "가장 좋은 방법"을 찾고 있다면 그런 다음 사용할 방법을 선택할 때 명심해야 할 또 다른 사항입니다.

LIMIT를 오프셋과 함께 사용하려면 (사용자가 페이지를 하나씩 페이징하는 대신 10000 페이지로 직접 이동하는 경우 필요합니다) 큰 으로 LIMIT의 성능을 향상시키기 위해 늦은 행 조회 에 대한이 기사를 읽을 수 있습니다 오프셋.


1
이것은 그것 같이 더 많은 것입니다 : P 내가 절대적으로 '새로운'식별자가 '나이'사람,보다 항상 큰 것을 암시의 승인 동안 대부분의 시간 이 참 케이스가 될 것입니다 때문에, 내 생각, 이것은 '좋은입니다 충분히'. 어쨌든, 당신이 시연했듯이, 적절한 페이지 매김 (큰 결과 집합에서 심각한 성능 저하가없는)은 특히 사소 limit 1000000, 10하지 않으며 작동하고 그것이 작동하기를 희망하며 아무 데나 도움이되지 않기를 바랍니다.
shylent

1
후기 조회 링크는 매우 유용합니다
pvgoddijn

1
id 주문에 "DESC"를 사용하면이 페이지 매김이 거꾸로 작동합니다. 나는 그것을 좋아한다!
데니스 하이덴

2
그러나 사람들이 현실 세계에서 얼마나 자주 ID로, 또는 insinuation으로, "날짜 생성"으로 주문하기를 원합니까?
RichieHH

좋은 포스트,하지만 area=width*height그건 문제가 있습니다 기록의 단지 양은 아니지만, 각 레코드의 크기도 메모리에 결과를 저장하는 요인이다 그래서
nothingisnecessary

43

쿼리에 대해 OFFSET 을 정의하십시오 . 예를 들어

1 페이지-(레코드 01-10) : 오프셋 = 0, 한계 = 10;

페이지 2-(11-20 레코드) 오프셋 = 10, 한계 = 10;

다음 쿼리를 사용하십시오.

SELECT column FROM table LIMIT {someLimit} OFFSET {someOffset};

2 페이지의 예 :

SELECT column FROM table
LIMIT 10 OFFSET 10;

1
2 페이지에 오프셋 = 10을 의미합니까?
Jenna Maiz

28

그것에 관한 문헌이 있습니다 :

주요 문제는 큰 사용으로 발생합니다 OFFSET. 이들은 절의 범위 선택에서 일종의 캐싱 또는 사전 계산 페이지에 OFFSET이르기까지 다양한 기술을 사용하지 않습니다 .idWHERE

INDEX 사용, Luke 에는 제안 된 솔루션이 있습니다 .


1
복잡한 쿼리의 각 페이징 쿼리에 대한 getiing max id는 실용적이지 않은 비 프로덕션 사용으로 순위, 행 번호 및 페이징 유형 간 페이징이 성능을 향상시킵니다.
Rizwan Patel

이 전략은 제공된 링크에서 고려되고 올바르게 평가됩니다. 그렇게 간단하지 않습니다.
Luchostein

제공된 링크는 기본 피벗 단일 피벗, 크로스 적용, 다중 CTE 또는 파생 테이블 메커니즘 만 충족하는 것 같습니다. 다시 나는 maxid가 건축 과잉을 얻는 것에 대한 그런 크기에 대한 쿼리를 다시 쓰는 나의 경우를지지한다! 후 다시에 대한 순열과 조합 n "은 정렬 순서로 열 수!
Rizwan 파텔

1
"Pagination done to right way"링크를 오해하고 있거나 필터링과 관련된 모든 쿼리에서 단순히 비현실적입니까?
contactmatt

1
@contactmatt 나는 당신의 이해를 공유합니다. 결국 전체 요구 사항을 효율적으로 구현할 수있는 방법이 없지만 원본을 중심으로 완화 된 변형을 수행 할 수있는 방법이없는 것 같습니다.
Luchostein 2016 년


6

당신은 또한 할 수 있습니다

SELECT SQL_CALC_FOUND_ROWS * FROM tbl limit 0, 20

테이블 크기를 다시 쿼리 할 필요가 없도록 select 문 (제한없이)의 행 개수는 동일한 select 문에 캡처됩니다. SELECT FOUND_ROWS ()를 사용하여 행 수를 얻습니다.


1
이것은 특히 비효율적입니다. *더 필요한 존재가 가져온보다 열 및 결과 SQL_CALC_FOUND_ROWS이 줄 결과에서 읽는 모든 사람들이 결과에 포함되지 않은 경우에도, 테이블의 행. 모든 열을 읽지 않는 별도의 쿼리에서 행 수를 계산하는 것이 훨씬 효율적입니다. 그런 다음 20 개의 행을 읽은 후 기본 쿼리가 중지 될 수 있습니다.
thomasrutter

확실합니까? 큰 테이블 SQL_CALC_FOUND_ROWS 및 다른 쿼리를 사용하지 않고 쿼리 시간을 정했습니다. 나는 시차를 보지 못했다. 어떤 방법 으로든 2 개의 쿼리를 수행하는 것보다 빠릅니다. 1-허용 가능한 한계 0 20에서 *를 선택한 다음 atable에서 count (*)를 선택하십시오.
surajz

1
예, 확실 합니다. 자세한 내용은 여기를 참조하십시오 . 인덱스를 사용하여 행을 필터링하는 경우 모든 경우에 SQL_CALC_FOUND_ROWS는 2 개의 개별 쿼리를 수행하는 것보다 상당히 느립니다. 드문 경우지만 색인을 사용하지 않거나 (이 단순화 된 예에서와 같이) WHERE 절이 없으며 MYISAM 테이블이므로 거의 차이가 없습니다 (동일한 속도입니다).
thomasrutter


4

쿼리 1 : SELECT * FROM yourtable WHERE id > 0 ORDER BY id LIMIT 500

쿼리 2 : SELECT * FROM tbl LIMIT 0,500;

작은 또는 중간 레코드로 쿼리 1을 더 빠르게 실행합니다. 레코드 수가 5,000 이상이면 결과가 비슷합니다.

500 개 레코드에 대한 결과 :

Query1은 9.9999904632568 밀리 초가 걸립니다.

Query2는 19.999980926514 밀리 초가 걸립니다.

8,000 개의 레코드 결과 :

Query1은 129.99987602234 밀리 초가 걸립니다.

Query2는 160.00008583069 밀리 초가 걸립니다.


에 색인을 추가해야합니다 id.
Maarten

6
어떻게 id > 0유용합니까?
Michel Jung

1
Maarten이 말했듯이,이 두 쿼리는 기본적으로 동일하게 보이고 아마도 같은 머신 레벨 명령으로 분류됩니다. 인덱싱 문제가 있거나 실제 버전의 MySQL이 있어야합니다.
HoldOffHunger

감사합니다, 당신의 대답을 보지
못했던

잘못된 예가 사용되었습니다. 와 offset(제한하는 제 인수 오프셋)가 여전히 다음 섹션 사이 복귀 후, 오프셋의 양을 폐기 한계에 모든 데이터를 선택하는 것 offsetlimit. where반면에 with 절을 사용하면 ONLY특정 부분을 쿼리 및 쿼리하기위한 시작 지점을 설정하게 됩니다.
senaps September

0

페이징은 단일 테이블에서 데이터를 가져올 때 간단하지만 여러 테이블을 조인하는 데이터를 검색 할 때는 복잡합니다. 다음은 MySql 및 Spring의 좋은 예입니다.
https://www.easycodeforall.com/zpagination1.jsp


언젠가 사라질 수있는 타사 사이트에 대한 링크를 공유하지 마십시오. 저자의 질문에 대답하고 싶다면 관련 코드를 게시하여 도움을 받으십시오.
브랜드가없는 Manchester
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.