MySQL : 행 수를 계산하는 가장 빠른 방법


117

MySQL에서 행 수를 계산하는 방법이 더 빠를까요?

이:

SELECT COUNT(*) FROM ... WHERE ...

또는 대안 :

SELECT 1 FROM ... WHERE ...

// and then count the results with a built-in function, e.g. in PHP mysql_num_rows()

첫 번째 방법은 분명히 데이터베이스 영역이고 내부적으로 이와 같은 것을 결정할 때 데이터베이스 엔진이 다른 어떤 사람보다 빠르기 때문에 첫 번째 방법이 더 빠르다고 생각할 것입니다.


1
아, 비슷한 질문을 찾았습니다 ( stackoverflow.com/questions/1855226/… ). 하지만, 내가 사용 SELECT 1하지 SELECT *. 차이가 있습니까?
Franz

모르겠지만이 두 답변이 동일하다고 생각할 수 있습니다. mysql 쿼리 최적화 프로그램이 각각에 대해 동일한 작업을 수행 할 수 있습니다. 전자가 후자보다 덜 모호하다고 말했습니다. 벤치 마크를 작성하고 테스트 해 보는 것은 어떻습니까?
Jesse Cohen

음, 다른 단어로 비슷한 질문을하여 SO의 검색 엔진 가시성을 향상 시키려고한다고 가정 해 보겠습니다.)
Franz

1
차이점은 PHP 측으로 전송되는 데이터의 양입니다. 열이 많을수록 SELECT *가 SELECT 1에 비해 상대적으로 느려집니다. 모든 열이 숫자 1 대신 검색되기 때문 mysql_query()입니다. 예를 들어 를 실행 하면 전체 결과 집합이 MySQL에서 PHP로 전송됩니다. 그 데이터로 할 수 있습니다.
toon81 2013

이와 같은 질문을하는 것은 통찰력이나 새로운 아이디어를 얻을 수있는 좋은 방법이지만 궁극적으로 더 빠른 속도를 원하는 특정 시나리오가있는 경우 테스트를 실행하여 가장 빠른 것이 무엇인지 확인해야합니다.
still_dreaming_1 dec.

답변:


124

COUNT(*)카운트 열 인덱스를 가져 오면 최상의 결과가 될 것입니다. MyISAM 엔진을 사용하는 Mysql은 실제로 행 수를 저장하지만 모든 행을 계산하려고 할 때마다 모든 행을 계산하지는 않습니다. (기본 키 열 기준)

행을 계산하기 위해 PHP를 사용하는 것은 그리 현명하지 않습니다. mysql에서 php로 데이터를 보내야하기 때문입니다. mysql 측에서 동일한 결과를 얻을 수 있는데 왜 그렇게합니까?

(가) 경우 COUNT(*)천천히, 당신은 실행해야 EXPLAIN쿼리에 인덱스가 실제로 사용하는 경우 확인하고 그들이 어디에 추가해야합니다.


다음은 가장 빠른 방법 COUNT(*)은 아니지만 실제로 적합하지 않은 경우가 있습니다. 결과 그룹화를 시작하면 COUNT실제로 모든 행을 계산하지 않는 문제가 발생할 수 있습니다 .

해결책은 SQL_CALC_FOUND_ROWS. 일반적으로 행을 선택하지만 총 행 수를 알아야 할 때 (예 : 페이징) 일반적으로 사용됩니다. 데이터 행을 선택할 때 SQL_CALC_FOUND_ROWSSELECT 뒤에 키워드를 추가하십시오 .

SELECT SQL_CALC_FOUND_ROWS [needed fields or *] FROM table LIMIT 20 OFFSET 0;

필요한 행을 선택한 후 다음 단일 쿼리로 개수를 가져올 수 있습니다.

SELECT FOUND_ROWS();

FOUND_ROWS() 데이터 선택 쿼리 직후에 호출해야합니다.


결론적으로 모든 것은 실제로 얼마나 많은 항목이 있고 WHERE 문에 무엇이 있는지에 달려 있습니다. 행이 많을 때 (수만, 수백만 이상) 인덱스가 사용되는 방식에주의를 기울여야합니다.


14
수정 : MyISAM행 수를 저장합니다. 같은 다른 스토리지 엔진은 행 수를 저장 InnoDB 하지 않으며 매번 모든 행을 계산합니다 .
Scrum Meister

1
당신은 당신이 단순히 행이 있는지 여부를 알아 할 때 가장 빠른 것이다 아십니까 : SELECT 1 FROM ... LIMIT 1SELECT COUNT(*) FROM ...?
Franz

1
어쨌든 데이터가 필요하고 페이지 매김 등의 카운트 만 원하는 경우 유용 할 것입니다. 데이터를 얻은 다음 프로그램의 행을 계산하는 것이 더 효율적입니다.
Tyzoid

6
엔진이 행 수를 저장하는지 여부는 관련이 없습니다. 질문은 WHERE조항 이 있음을 분명히 나타냅니다 .
Álvaro González

1
@Franz SELECT COUNT(*) FROM ...는 무엇을 스캔해야하는지에 따라 상당한 시간이 걸릴 수 있습니다 (예 : 매우 큰 테이블 또는 수백만 / 십억 / 수조 행의 인덱스). SELECT 1 FROM ... LIMIT 1첫 번째 행으로 제한하므로 즉시 반환됩니다.
jbo5112 2014

59

팀 동료들과 이야기를 나눈 후 Ricardo는 더 빠른 방법은 다음과 같다고 말했습니다.

show table status like '<TABLE NAME>' \G

그러나 결과가 정확하지 않을 수 있음을 기억해야합니다.

명령 줄에서도 사용할 수 있습니다.

$ mysqlshow --status <DATABASE> <TABLE NAME>

추가 정보 : http://dev.mysql.com/doc/refman/5.7/en/show-table-status.html

mysqlperformanceblog 에서 전체 토론을 찾을 수 있습니다.


2
InnoDB의 경우 이것은 근사치입니다.
Martin Tournoij

2
count (*)가 문자 그대로 몇 시간이 걸릴 수있는 매우 큰 테이블의 행 수에 대한 대략적인 아이디어가 필요할 때 알아두면 좋습니다!
Mark Hansen

이것은 내 머리카락을 모두 뽑아내는 것을 구했습니다. COUNT (*)는 내 데이터베이스에서 3,300 만 개 이상의 행을 모두 계산하는 데 오랜 시간이 걸렸습니다. 어쨌든 병렬화 된 행 삭제 기능이 작동하는지 여부 만 알고 싶었습니다. 정확한 번호는 필요하지 않았습니다.
joemar.ct

1
+1 테이블 상태 대신 "COUNT (*)"를 사용하는 것이 "정확성"이 아닌 "가장 빠름"에 대한 것과 같이이 질문에 대한 정답이어야합니다.
lepe

2
사용 SHOW TABLE STATUS(또는 동등 SELECT의 것은 information_schema) 빠르지 만 그것은 처리하지 않습니다 WHERE절을. MyISAM의 경우 정확하지만 InnoDB의 경우 부정확합니다 (때로는 2 배).
Rick James

29

좋은 질문, 좋은 답변. 누군가이 페이지를 읽고 해당 부분을 놓친 경우 결과를 신속하게 표시하는 방법은 다음과 같습니다.

$counter = mysql_query("SELECT COUNT(*) AS id FROM table");
$num = mysql_fetch_array($counter);
$count = $num["id"];
echo("$count");

5
mysql_query는 PHP 5.5.0부터 사용되지 않는 함수입니다.
Omar Tariq

8
왜 안돼 as count? id처음 보면 혼란 스럽습니다.
Orkhan Alikhanov

질문에 대답하지 않는다
mentalic

17

이 쿼리 ( bayuah가 게시 한 것과 유사 )는 데이터베이스 내부의 모든 테이블 수에 대한 멋진 요약을 보여줍니다. ( Ivan Cachicatari 의 간단한 저장 프로 시저 버전으로 강력하게 추천합니다).

SELECT TABLE_NAME AS 'Table Name', TABLE_ROWS AS 'Rows' FROM information_schema.TABLES WHERE TABLES.TABLE_SCHEMA = '`YOURDBNAME`' AND TABLES.TABLE_TYPE = 'BASE TABLE'; 

예:

+-----------------+---------+
| Table Name      | Rows    |
+-----------------+---------+
| some_table      |   10278 |
| other_table     |     995 |

그것은 나에게 결과를 준다. 그러나 count (1)의 결과와 이것은 다릅니다. 이 방법은 항상 개수 쿼리보다 적은 수를 제공합니다. 이견있는 사람?
Ayyappan Sekar

3
독자에게 참고하십시오. 이 방법은 매우 빠르지 만 InnoDB를 사용하는 경우에 저장된 값 information_schema이 반환되는 값 과 같지 않기 때문에 대략적인 행 수로 작업 할 수있는 경우에만 적용 할 수 있습니다 SELECT count(*) FROM. 엄격한 값이 필요한 경우이 방법은 MyISAM 테이블에서만 엄격한 값을 제공합니다. InnoDB에서 행 수는 대략적인 근사치입니다.
Bartosz Firyn

13

아래 내용이 가장 빠른 응답 시간을 제공한다는 것을 항상 이해했습니다.

SELECT COUNT(1) FROM ... WHERE ...

1
SELECT 1 FROM ... WHERE ...가 더 빠르지 않습니까?
patrick

3
@patrick- SELECT 1 ...만큼의 행을 반환 WHERE하고 LIMIT요청하며 모두 "1"이됩니다.
Rick James

1
show table status like '<TABLE NAME>' 이것은 훨씬 더 빠를 것입니다.
deep

@deep- WHERE절이 있으면 관련이 없습니다 . 그리고 InnoDB의 경우 이는 추정치 일뿐입니다.
릭 제임스

@RickJames 맞아요!
deep

6

전체 결과 집합의 개수를 가져와야하는 경우 다음 접근 방식을 사용할 수 있습니다.

SELECT SQL_CALC_FOUND_ROWS * FROM table_name LIMIT 5;
SELECT FOUND_ROWS();

이것은 일반적으로 사용하는 것보다 빠르지는 않지만 COUNT내부적으로 계산을 수행하고 사용자에게 데이터를 다시 보내지 않으므로 성능 향상이 의심되기 때문에 반대의 경우라고 생각할 수 있습니다.

이 두 쿼리를 수행하는 것은 총계를 얻기위한 페이지 매김에는 좋지만 특히 WHERE절 을 사용하는 경우에는 적합하지 않습니다 .


Intersting. 가장 일반적인 데이터베이스 시스템에서 작동합니까? MySQL, Postgres, SQLite ...?
Franz

4
이것은 실제로 COUNT (*)를 사용하는 것보다 빠르지 않습니다. stackoverflow.com/questions/186588/…을
toon81

2
이 기능을 사용할 때는 매우주의해야합니다. 한때 무분별한 사용으로 인해 전체 생산 환경이 중단되었습니다. 자원 집약적이므로주의해서 사용하십시오.
Janis Peisenieks

6

COUNT(*)vs COUNT(id)(id는 테이블의 기본 키-인덱싱 됨) 의 실행 시간을 비교하기 위해 몇 가지 벤치 마크 를 수행했습니다 .

시도 횟수 : 10 * 1000 쿼리

결과 : COUNT(*)7 % 더 빠름

그래프보기 : 벤치 마크 그래프

내 조언은 다음을 사용하는 것입니다. SELECT COUNT(*) FROM table


1
참고로으로 계산하는 일반적인 방법도 있습니다. COUNT(1)여기에서 벤치 마크를 확인하는 것이 흥미로울 것입니다.
Sliq

4

이 시도:

SELECT
    table_rows "Rows Count"
FROM
    information_schema.tables
WHERE
    table_name="Table_Name"
AND
    table_schema="Database_Name";

@lepe 죄송합니다. 내 말은, 반대 투표를 한 사람이 왜 그렇게했는지 설명 해주면 모든 사람이 그것에 대해 배울 수 있다는 것이 정말 좋습니다.
bayuah

1
이렇게하면 대략적인 답변을 빠르게 얻을 수 있습니다. 정확한 답변이 필요하면 수행 select count(*) from table_name하거나 다른 작업을 수행해야합니다 . dba.stackexchange.com/questions/151769/...
Programster

@Programster 감사합니다. 거의 1 년 동안 나를 어둠 속에 두는 것보다 낫습니다.
bayuah

1
@bayuah 마지막 댓글이 무슨 뜻인지 잘 모르겠습니다. 나는 당신이 당신의 대답에 반대표를 던진 사람이라고 생각할 수 있습니다.
Programster

1
@Programster 아니요, 죄송합니다. 그런 뜻이 아닙니다. 설명 해주셔서 감사합니다. 그래서 Downvoter가 그렇게했을 때 생각했던 것을 추측 할 수 있습니다.
bayuah

3

아마도 당신은 SELECT max(Id) - min(Id) + 1. 이것은 ID가 순차적이고 행이 삭제되지 않은 경우에만 작동합니다. 그러나 매우 빠릅니다.


3
주의 : 서버는 때때로 자동 증분 값> 1 (백업 이유로)을 사용하므로이 솔루션이 좋지만 먼저 DB 구성을 확인해야합니다.
Alex

1

EXPLAIN SELECT id FROM ....나를 위해 트릭을했다. rows결과 열 아래의 행 수를 볼 수 있습니다.


0

나는 때때로 6 천만 개의 레코드가있는 독일 정부를 위해 테이블을 처리했습니다.

그리고 전체 행을 여러 번 알아야했습니다.

그래서 우리 데이터베이스 프로그래머들은 모든 테이블에 레코드 1이 항상 총 레코드 번호가 저장되는 레코드라고 결정했습니다. INSERT 또는 DELETE 행에 따라이 번호를 업데이트했습니다.

우리는 다른 모든 방법을 시도했습니다. 이것이 가장 빠른 방법입니다.


1
해당 행을 업데이트 한 방법에 대한 세부 정보는 무엇입니까? 즉, 테이블에 대한 잘못된 디자인이지만 모든 행이 타는 데 낭비되는 정수가 필요하다는 것을 의미합니다.
Drew

5
네, 정말 멍청하네요. 모든 쿼리에서 첫 번째 행을 무시해야합니다. 총계 테이블을 만들고 트리거를 기반으로 채 웁니다. 삽입시 사용자 테이블, 합계 테이블 업데이트. 삭제, 업데이트 합계 테이블의 사용자 테이블.
HTMLGuy

-1

기본 키에 where 조건이있는 count (*) 문은 전체 테이블 스캔을 피하는 데 훨씬 더 빨리 행 수를 반환했습니다.

SELECT COUNT(*) FROM ... WHERE <PRIMARY_KEY> IS NOT NULL;

이것은 나보다 훨씬 빠릅니다.

SELECT COUNT(*) FROM ...
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.