[mysql] 이중 쿼리없이 MySQL 페이지 매김?

MySQL 쿼리에서 결과 수를 가져 오는 동시에 결과를 제한하는 방법이 있는지 궁금합니다.

페이지 매김이 작동하는 방식 (내가 이해하는대로), 먼저 다음과 같은 작업을 수행합니다.

query = SELECT COUNT(*) FROM `table` WHERE `some_condition`

num_rows (query)를 얻은 후 결과 수를 얻었습니다. 하지만 실제로 결과를 제한하려면 다음과 같은 두 번째 쿼리를 수행해야합니다.

query2 = SELECT COUNT(*) FROM `table` WHERE `some_condition` LIMIT 0, 10

내 질문 : 어쨌든 주어진 총 결과 수를 검색하고 단일 쿼리에서 반환되는 결과를 제한하는 방법이 있습니까? 또는이를 수행하는 더 효율적인 방법. 감사!



답변

아니요, 페이지 매기기를 원하는 응용 프로그램의 수입니다. 쿼리를 두 번 수행하지만 신뢰할 수 있고 방탄입니다. 그러나 몇 초 동안 카운트를 캐시하면 많은 도움이됩니다.

다른 방법은 SQL_CALC_FOUND_ROWS절 을 사용한 다음을 호출하는 것 SELECT FOUND_ROWS()입니다. FOUND_ROWS()나중에 호출 을해야한다는 사실과는 별개 로 이것에 문제가 있습니다 . MySQL 에는 이것이 ORDER BY두 쿼리의 순진한 접근 방식보다 큰 테이블에서 훨씬 느리게 만드는 쿼리 에 영향을 미치는 간지럼 이 있는 버그 가 있습니다 .


답변

나는 거의 두 가지 쿼리를하지 않습니다.

필요한 것보다 하나 더 많은 행을 반환하고 페이지에 10 개만 표시하고 더 많은 행이 표시되면 “다음”버튼을 표시합니다.

SELECT x, y, z FROM `table` WHERE `some_condition` LIMIT 0, 11
// iterate through and display 10 rows.

// if there were 11 rows, display a "Next" button.

검색어는 가장 관련성이 높은 순서로 먼저 반환되어야합니다. 대부분의 사람들은 412 개 중 236 페이지로가는 것에 관심이 없을 것입니다.

Google 검색을했는데 결과가 첫 페이지에 없으면 9 페이지가 아닌 2 페이지로 이동합니다.


답변

이중 쿼리를 방지하는 또 다른 방법은 먼저 LIMIT 절을 사용하여 현재 페이지에 대한 모든 행을 가져온 다음 최대 행 수가 검색된 경우에만 두 번째 COUNT (*) 쿼리를 수행하는 것입니다.

대부분의 응용 프로그램에서 가장 가능성이 높은 결과는 모든 결과가 한 페이지에 맞는 것이며 페이지 매김을 수행해야하는 것은 표준이 아니라 예외입니다. 이러한 경우 첫 번째 쿼리는 최대 결과 수를 검색하지 않습니다.

예를 들어, stackoverflow 질문에 대한 답변은 두 번째 페이지에 거의 넘치지 않습니다. 답변에 대한 의견은 모두를 표시하는 데 필요한 5 개 정도를 넘지 않습니다.

따라서 이러한 응용 프로그램에서는 먼저 LIMIT를 사용하여 쿼리를 수행 한 다음 해당 제한에 도달하지 않는 한 두 번째 COUNT (*) 쿼리를 수행 할 필요없이 정확히 몇 개의 행이 있는지 알 수 있습니다. 대부분의 상황을 다룹니다.


답변

대부분의 상황에서 직관적이지 않은 것처럼 보이지만 두 개의 개별 쿼리로 수행하는 것이 하나에서 수행하는 것보다 훨씬 빠르고 리소스 집약적이지 않습니다.

SQL_CALC_FOUND_ROWS를 사용하면 큰 테이블의 경우 두 개의 쿼리를 실행하는 것보다 훨씬 느리고 쿼리가 훨씬 느려집니다. 첫 번째 쿼리에는 COUNT (*)가 있고 두 번째 쿼리에는 LIMIT가 있습니다. 그 이유는 SQL_CALC_FOUND_ROWS로 인해 이전이 아닌 행 페치 한 LIMIT 절이 적용되므로 제한을 적용하기 전에 가능한 모든 결과에 대해 전체 행을 페치하기 때문입니다. 실제로 데이터를 가져 오기 때문에 인덱스로는 만족할 수 없습니다.

두 쿼리 접근 방식을 사용하면 첫 번째 쿼리는 COUNT (*) 만 가져오고 실제로는 실제 데이터를 가져 오지 않습니다. 일반적으로 인덱스를 사용할 수 있고 실제 행 데이터를 가져올 필요가 없기 때문에 훨씬 더 빠르게 충족 될 수 있습니다. 보는 모든 행. 그런 다음 두 번째 쿼리는 첫 번째 $ offset + $ limit 행만보고 반환하면됩니다.

MySQL 성능 블로그의이 게시물은 이에 대해 자세히 설명합니다.

http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/

페이지 매김을 최적화에 대한 자세한 내용은 확인 이 게시물이 게시물을 .


답변

내 대답이 늦을 수 있지만 두 번째 쿼리 (제한 있음)를 건너 뛰고 백엔드 스크립트를 통해 정보를 필터링 할 수 있습니다. 예를 들어 PHP에서는 다음과 같이 할 수 있습니다.

if($queryResult > 0) {
   $counter = 0;
   foreach($queryResult AS $result) {
       if($counter >= $startAt AND $counter < $numOfRows) {
            //do what you want here
       }
   $counter++;
   }
}

그러나 물론 고려할 레코드가 수천 개이면 비효율적입니다. 미리 계산 된 개수를 살펴 보는 것이 좋습니다.

다음은 주제에 대한 좋은 읽기입니다.
http://www.percona.com/ppc2009/PPC2009_mysql_pagination.pdf


답변

query = SELECT col, col2, (SELECT COUNT(*) FROM `table`) AS total FROM `table` WHERE `some_condition` LIMIT 0, 10


답변

2020 년에 해답을 찾고있는 사람을 위해. MySQL 문서에 따라 :

“SQL_CALC_FOUND_ROWS 쿼리 수정 자와 함께 제공되는 FOUND_ROWS () 함수 는 MySQL 8.0.17에서 더 이상 사용되지 않으며 향후 MySQL 버전에서 제거 될 예정입니다. 대신 LIMIT로 쿼리를 실행 한 다음 COUNT (*)로 두 번째 쿼리를 실행하는 것이 좋습니다. LIMIT없이 추가 행이 있는지 확인합니다. “

그게 해결 될 것 같아요.

https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_found-rows