M. David Allen은 10년 넘게 거의 모든 프로그래밍 언어와 다양한 유형의 데이터베이스 시스템을 다뤄온 풀스택 소프트웨어 엔지니어이자 기업가입니다. 이전에는 금융, 의료, 정부 등 다양한 산업 분야에서 일했으며, 주로 대규모 데이터 통합 문제, 응용 연구 전환, 신기술 혁신에 중점을 두었습니다. 그는 버지니아 커먼웰스 대학교에서 석사 학위를 받았지만, 정규 교육을 떠난 이후에도 여전히 기술을 공부하는 학생으로 남아 있습니다.
설정
이 튜토리얼에서는 다음과 같이 맥주 샘플 데이터 세트 를 사용하면 쉽게 따라할 수 있습니다. 아직 Couchbase가 설치되어 있지 않다면 도커와 카우치베이스 도커 이미지 페이지의 간단한 지침을 따르세요. 를 사용하여 테스트용 Couchbase 인스턴스를 빠르게 설정할 수 있습니다. Couchbase가 설치된 상태에서 docker run -d -name db -p 8091-8094:8091-8094 -p 11210:11210 Couchbase 명령을 실행하기만 하면 시작됩니다. 해당 페이지에 설명된 몇 가지 설정 프롬프트를 따르고 나면 데이터를 사용할 준비가 된 것입니다.
사용 사례 - 페이징이란 무엇이며 왜 페이징을 해야 하나요?
가상의 프런트엔드 맥주 애플리케이션에서 사용자에게 맥주 표를 보여주고 각 맥주를 평가하도록 하려는 매우 일반적인 요구 사항을 고려해 보겠습니다. 문제는 데이터베이스에 5,000개가 넘는 맥주가 포함되어 있다는 것입니다. 매번 전체 데이터 세트를 브라우저로 전송하는 것은 낭비이며 웹 애플리케이션의 페이지 로딩 속도가 매우 느려질 것입니다.
사용자에게 처음 10개의 맥주만 표시하는 것이 훨씬 더 좋습니다. 그런 다음 '다음' 버튼을 클릭하여 다음 페이지로 이동하거나 무한 스크롤 플러그인을 사용하면 더 좋습니다(예 ngInfiniteScroll 각진 또는 리액트-인피니트 의 경우) 사용자에게 데이터베이스의 레코드를 점진적으로 더 많이 표시할 수 있습니다.
코드를 보여주세요!
1 2 3 4 5 6 7 8 9 |
선택 이름, 카테고리, abv 에서 `맥주-샘플` 어디 brewery_id 는 not 누락 주문 BY 이름 오프셋 0 LIMIT 10; |
그러면 예상되는 데이터가 반환됩니다:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
[ { "abv": 0, "category": "북미 라거", "name": "#17 크림 에일" }, { "abv": 0, "name": "#40 골든 라거" }, { "abv": 0, "category": "기타 스타일", "name": "#42 크림 에일" }, /* (...) */ |
두 번째 페이지의 결과를 얻으려면 OFFSET에 LIMIT만 추가하면 됩니다. 예를 들어 OFFSET 10 LIMIT 10은 두 번째 페이지가 됩니다. 이를 일반화하기 위해 n번째 페이지에 도달하기 위해 OFFSET으로 몇 개의 레코드를 건너뛰어야 할까요? 항상 n * 페이지 크기입니다.
이 간단한 수식을 사용하면 모든 시나리오에 일반화할 수 있습니다. 한 번에 20개의 결과를 표시하고 싶은데 사용자가 11번째 페이지로 바로 이동하기를 원한다면 어떻게 해야 할까요? 문제없습니다. LIMIT 20 OFFSET 20 * 11이면 됩니다. 그러면 애플리케이션 엔드포인트는 데이터베이스를 검색하든, 단순히 맥주를 이름으로 나열하든 매번 똑같은 쿼리 로직을 사용할 수 있습니다. 쿼리가 아무리 복잡하더라도 LIMIT와 OFFSET만 조정하면 모두 같은 페이지에 있는 것입니다.
어떻게 작동하나요?
여기서 마법은 세 개의 N1QL 절의 조합입니다: LIMIT, 오프셋및 주문 기준. 작업을 완료하는 데 모두 필요하므로 각각에 대해 간단히 살펴 보겠습니다.
- LIMIT 는 말 그대로 작동합니다. Couchbase가 반환할 레코드 수를 제한하고 페이지 크기를 효과적으로 강제합니다(한 번에 10개의 맥주만 반환하고 5,000개는 반환하지 않습니다).
- 오프셋 는 카우치베이스가 문서 반환을 시작하기 전에 건너뛸 레코드 수를 알려줍니다. SQL에 익숙하다면 SQL의 SKIP처럼 작동합니다. OFFSET 절은 전체 데이터 집합을 한 번에 한 청크씩 앞으로 이동하는 방식입니다.
- 주문 기준 는 데이터베이스에서 반환되는 특정 순서를 보장합니다. 이는 중요한데, 카우치베이스는 사용자가 요청하지 않는 한 결과의 특정 순서를 보장하지 않기 때문입니다. 이전 쿼리에서는 이름으로 주문할 때 #17 크림 에일이 첫 번째 결과로 나타났습니다. ORDER BY를 사용하지 않았다면 #17 크림 에일이 세트의 어느 위치에 표시될지 예측할 수 없었을 것이며, 카우치베이스가 쿼리를 실행하는 방식에 따라 여러 페이지에 표시될 수도 있었을 것입니다!
간단히 말해, 카우치베이스가 이름별로 주문된 모든 맥주의 목록을 작성한다고 상상해 보세요(ORDER BY). 페이지 매김은 그 중 10개씩 일괄 처리하는 것입니다(LIMIT 10). 그런 다음 각 페이지는 주문한 전체 목록을 건너뛰고 다음 페이지의 시작 지점으로 이동합니다(OFFSET).
직접 설명하세요, 카우치베이스.
마지막 예로, 다른 N1QL 쿼리와 마찬가지로 쿼리 앞에 "설명"을 넣는 것만으로도 작동 방식에 대한 많은 인사이트를 얻을 수 있습니다. 이렇게 하면 Couchbase가 무엇을 할 계획인지 알려줍니다.
1 2 3 4 5 6 7 8 9 |
설명 선택 이름, 카테고리, abv 에서 `맥주-샘플` 어디 brewery_id 는 not 누락 주문 BY 이름 오프셋 0 LIMIT 10; |
(이 쿼리를 직접 사용해 보세요!) 출력은 다소 길기 때문에 여기에 붙여넣지 않고, 이 쿼리로 Couchbase가 수행하는 작업을 요약해 보겠습니다.
- 먼저 맥주 샘플 버킷을 1차 스캔하고 문서를 가져옵니다.
- 동시에 다음을 필터링합니다:
- brewery_id가 있는 레코드(이는 레코드가 맥주 문서가 아니라 맥주임을 알려줍니다)
- 이름, 카테고리 및 광고비 속성(우리가 요청한 것)을 투영합니다.
- 그런 다음 이름별로 결과를 정렬합니다.
- 다음에 오프셋이 적용되어 첫 번째 X 레코드를 건너뛰고 전혀 반환하지 않습니다.
- 마지막으로, 다음 n개의 레코드를 읽고 그 이후의 레코드는 모두 무시하는 방식으로 LIMIT를 적용합니다.
언제 끝나요?
한 번에 한 페이지씩 데이터를 이동하는 경우, 언제 멈춰야 하는지도 알아야 합니다. 여기에는 두 가지 접근 방식이 있는데, 한 가지 방법은 페이지를 무한정 계속 진행하면 결국 데이터가 부족해집니다. 반면에 몇 개의 페이지가 있는지 미리 계산한 다음 그 수에 도달할 때까지 반복할 수도 있습니다.
그러한 문서 세트가 없다는 것을 잘 알면서 1,000개의 결과 중 7번째 페이지를 요청하면 어떻게 될까요?
1 2 3 4 5 6 7 8 9 |
선택 이름, 카테고리, abv 에서 `맥주-샘플` 어디 brewery_id 는 not 누락 주문 BY 이름 오프셋 7 * 1000 LIMIT 1000; |
끝을 지나치면 빈 배열이 나오니 걱정하지 마세요.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
{ "결과": [], "metrics": { "elapsedTime": "465.446327ms", "실행 시간": "465.384101ms", "resultCount": 0, "결과 크기": 0, "sortCount": 5891 } } |
참고로, 빈 배열은 다음과 같은 말도 안 되는 요청을 하면 얻을 수 있는 결과이기도 합니다:
1 2 3 4 5 6 7 8 9 |
선택 이름, 카테고리, abv 에서 `맥주-샘플` 어디 brewery_id 는 not 누락 주문 BY 이름 오프셋 -5 LIMIT -10; |
잠깐....왓?!?! 이 쿼리는 출력 세트의 시작 전에 5개의 레코드를 시작하고 -10개 이하의 레코드를 반환하도록 요청하고 있습니다. 시작 전 5개의 레코드는 아무것도 아닙니다. 그리고 -10개 이하의 레코드는 아무것도 아닙니다. 그래서 당신은....nothing을 얻습니다!
이 동작은 매우 편리하며, 레코드가 부족할 때 명확하고 다른 소프트웨어 계층의 다른 많은 가정과도 잘 어울립니다. 페이징을 지원하는 REST API를 사용해 본 적이 있다면 일반적으로 이러한 방식으로 작동합니다. 예를 들어 다음과 같은 REST API 엔드포인트를 쉽게 상상할 수 있습니다(http://cool-app.com/beers?limit=10&page=6000). 백엔드에 이러한 엔드포인트를 작성했다면 해당 N1QL 쿼리가 어떻게 생성되는지 쉽게 알 수 있으며, 사용자가 이상한 페이지 번호를 제공하더라도 엔드포인트가 올바른 작업을 수행할 것입니다.
하지만 몇 페이지가 나올지 미리 알고 싶다면 어떻게 해야 하나요?
이것도 간단합니다. 각 페이지에 n개의 레코드가 있고 총 레코드 수를 알고 있다면 총계를 n으로 나누고 그 수의 상한을 구하면 Couchbase에 얼마나 많은 잠재적 페이지가 있는지 알 수 있습니다.
1 2 3 |
선택 CEIL(카운트(*) / 10) 에서 `맥주-샘플` 어디 brewery_id 는 not 누락 |
이렇게 하면 내 로컬 데이터베이스에서 590개가 나옵니다. 맥주 문서가 정확히 5,891개이므로 10개의 세트가 589개이고 최종 페이지에는 1개의 문서만 있다는 뜻입니다. 5,891 / 10 = 589.1이므로 N1QL을 사용합니다. CEIL 기능 를 사용하여 정수의 페이지 수를 얻어야 합니다. 어떤 프런트엔드 애플리케이션이든 0.1페이지를 표시하지 않을 것이기 때문입니다.
양조장 및 기타 문서를 제외하고 맥주 문서로만 문서를 줄이려면 여기에 WHERE 절이 필요하다는 것을 명심하세요. WHERE가 누락되면 확실히 잘못된 번호를 얻을 수 있습니다.