InfraMySQL

MySQL : SQL_CALC_FOUND_ROWS()

SQL_CALC_FOUND_ROWS는 SELECT 쿼리에 사용되는 MySQL 힌트로 SELECT 쿼리에 의해 반환되는 전체 row의 개수를 임시로 저장하는 역할을 합니다.
만약, SELECT 쿼리에 LIMIT 절이 포함되어 있는 경우에는 LIMIT 절을 적용하지 않은 전체 row의 개수를 임시로 저장합니다.
임시로 저장된 row의 개수는 SELECT FOUND_ROWS()가 실행될 때 반환됩니다.

SQL_CALC_FOUND_ROWS와 관련된 자세한 사항은 아래의 링크를 참고하십시요.
http://www.mysqlkorea.com/sub.html?mcode=develop&scode=01&lang=k&m_no=21838&cat1=12&cat2=359&cat3=374

예를 들어, 게시판에서 페이징을 구현할 때엔 일반적으로 페이징을 하기 위해 전체 게시물의 개수를 알기 위한 SELECT COUNT(*)쿼리와 화면에 표시되는 (특정 영역의) 데이터를 SELECT 하기 위한 쿼리를 별도로 작성하여 실행하게 됩니다.

같은 조건을 갖는 두 개의 쿼리를 별도로 작성하기 위해 소스 코드가 복잡해지는 경우가 많은데, SQL_CALC_FOUND_ROWS를 사용하면 하나의 쿼리를 사용하여 깔끔하게 구현할 수 있게 됩니다.

MySQL 매뉴얼에 의하면, SQL_CALC_FOUND_ROWS을 사용할 경우 그렇지 않은 경우에 비해 속도가 빨라진다고 했는데, 작업을 하다 보니 이상한 점이 있어 간단히 테스트를 해 보았습니다.

테스트에 사용된 테이블의 전체 건수는 32,959건이었고, row의 평균 크기는 431 byte였습니다.

소스를 살짝 변경하여 아래와 같이 3가지 유형으로 운영되었을 때의 MySQL 서버의 CPU 사용률, MySQL 네트워크 트래픽(sent), 웹 페이지 로딩 시간을 각각 측정해 보았습니다. (측정값은 최댓값의 근사치입니다.)

  1. SELECT + mysql_data_seek()
    LIMIT 절을 사용하지 않고 SELECT를 실행한 후, 소스 코드에서 mysql_data_seek()를 사용하여 특정 위치의 데이터에 접근(점프) 하여 화면에 표시하는 방식
    (전체 게시물의 건수를 알기 위한 별도의 SELECT COUNT(*) 쿼리를 사용하지 않음)

  2. SELECT COUNT() + SELECT ~ LIMIT
    가장 일반적인 방식으로 전체 게시물 건수를 알기 위한 SELECT COUNT(
    ) 쿼리와 특정 영역의 데이터를 표시하기 위한 SELECT ~ LIMIT 쿼리를 별도로 작성하여 실행하는 방식

  3. SELECT SQL_CALC_FOUND_ROWS ~ LIMIT
    SQL_CALC_FOUND_ROWS를 사용하여 한 번에 SQL을 작성하여 실행하는 방식

CaseMySQL 서버 CPU 사용률MySQL 네트워크 트래픽웹 페이지 로딩시간
1. SELECT + mysql_data_seek()41%1.2 MB0.83 sec
2. SELECT COUNT(*) + SELECT ~ LIMIT11%15.5 KB0.36 sec
3. SELECT SQL_CALC_FOUND_ROWS ~ LIMIT27%15.6 KB0.65 sec
  • 각 수치는 Case 간의 상대치로 생각해 주시기 바랍니다.

테스트해 본 결과, MySQL 매뉴얼의 내용과 달리 SQL_CALC_FOUND_ROWS를 사용(Case 3)했을 때 기존의 방식(Case 2)에 비해 전체적으로 성능이 저하된다는 것을 알 수 있었습니다.
그러나 Case 1의 방식에 비해서는 훨씬 좋은 성능을 보여 주었습니다.

테스트 결과상으로는 SQL_CALC_FOUND_ROWS를 사용하는 것이 불리하지만, 운영환경에 따라 불리함의 의미가 달라질 수도 있을 것 같습니다.

테스트를 진행할 때는 각각의 실행 결과를 정확히 알기 위해 MySQL의 Query Cache 기능을 제한하였는데, Query Cache 기능을 활성화한 상태에서 Query Cache에 cache 된 내용이 사용되는 경우에는 Case 2와 Case 3의 성능이 거의 같게 나왔습니다.

따라서 Query Cache의 사용률이 높은 환경이라면, SQL_CALC_FOUND_ROWS를 사용하여 소스의 복잡도가 낮추는 것이 훨씬 유용하지 않을까 생각됩니다.

출처: https://blog.naver.com/hschoi82/20050239561