문제

나는 일반적으로 다음과 같은 쿼리를하는 것이 나쁜 생각이라는 것을 알고 있습니다.

SELECT * FROM `group_relations`

그러나 카운트를 원할 때 테이블이 변경 될 수 있지만 여전히 동일한 결과를 얻을 수 있으므로이 쿼리로 이동해야합니다.

SELECT COUNT(*) FROM `group_relations`

또는 더 많은 사양입니다

SELECT COUNT(`group_id`) FROM `group_relations`

후자가 잠재적으로 더 빠를 수 있다고 생각하지만 고려해야 할 다른 것들이 있습니까?

업데이트:이 경우 InnoDB를 사용하고 있습니다. 더 구체적이지 않아서 죄송합니다.

도움이 되었습니까?

해결책

해당 열이 Null이 아닌 경우 두 쿼리가 모두 동일합니다. group_id에 null 값이 포함 된 경우

select count(*)

모든 행을 계산합니다

select count(group_id)

group_id가 null이 아닌 행만 계산합니다.

또한 MySQL과 같은 일부 데이터베이스 시스템은 Count (*)를 요청할 때 최적화를 사용하여 이러한 쿼리를 특정 쿼리보다 약간 빠르게 만듭니다.

개인적으로, 단지 계산할 때, 나는 널과 함께 안전한면에있는 카운트 (*)를하고 있습니다.

다른 팁

내가 올바르게 기억한다면, mysql count (*)에서 모든 행을 계산하는 반면, count (column_name)는 주어진 열에서 널 값이 아닌 행만 계산합니다.

COUNT (*) COUNT (COUNCELD 열)는 지정된 열에서 널 값이없는 행만 계산합니다.

MySQL에서 주목해야합니다.

행 카운트가 캐시되기 때문에 Count ()는 * 또는 null 열의 MyISAM 테이블에서 매우 빠릅니다. InnoDB에는 행 카케 팅이 없으므로 열이 무일하게 여부에 관계없이 Count (*) 또는 Count (column_name)의 성능 차이가 없습니다. 차이점에 대한 자세한 내용을 읽을 수 있습니다 이 게시물 MySQL Performance 블로그에서.

시도하면 SELECT COUNT(1) FROMGroup_relations 열에서 정보를 검색하려고하지 않기 때문에 조금 더 빠릅니다.

편집 : 방금 연구를했는데 이것이 일부 DB에서만 발생한다는 것을 알았습니다. SQLServer에서는 1 또는 *를 사용하는 것이 동일하지만 Oracle에서는 1을 사용하는 것이 더 빠릅니다.

http://social.msdn.microsoft.com/forums/en-us/transactsql/thread/9367c580-087a-4fc1-bf88-91a51a4ee018/

SQLServer와 같이 Parser는 쿼리를 선택하여 (1)을 변경하는 것으로 보입니다. 내가 어떤 식 으로든 당신을 오도한다면 죄송합니다.

나는 이것에 대해 궁금했다. 문서와 이론적 답변을 읽는 것은 괜찮지 만 경험적 증거와 균형을 맞추는 것을 좋아합니다.

5,607,997 개의 레코드가있는 MySQL 테이블 (InnoDB)이 있습니다. 테이블은 내 개인 샌드 박스에 있으므로 내용이 정적이며 다른 사람이 서버를 사용하지 않는다는 것을 알고 있습니다. 나는 이것이 효과적으로 성능에 대한 모든 외부 영향을 효과적으로 제거한다고 생각합니다. auto_increment 1 차 키 필드 (ID)가있는 테이블이 있는데, 내가 알지 못하는 곳은 내가 where 조항 테스트 (id가 null이 아닌 곳)에 사용할 수 없을 것입니다.

실행중인 테스트에서 볼 수있는 유일한 다른 결함은 캐시입니다. 쿼리가 처음 실행되는 것은 항상 동일한 인덱스를 사용하는 후속 쿼리보다 느리게됩니다. 아래를 캐시 파종 호출이라고 언급하겠습니다. 조금만 혼합하기 위해 나는 그것을 아는 Where 조항과 함께 그것을 달리면서 데이터에 관계없이 항상 true를 평가할 것입니다 (true = true).

여기에 내 결과가 있습니다.

QueryType

      |  w/o WHERE          | where id is not null |  where true=true

세다()

      |  9 min 30.13 sec ++ | 6 min 16.68 sec ++   | 2 min 21.80 sec ++
      |  6 min 13.34 sec    | 1 min 36.02 sec      | 2 min 0.11 sec 
      |  6 min 10.06 se     | 1 min 33.47 sec      | 1 min 50.54 sec

카운트 (ID)

      |  5 min 59.87 sec    | 1 min 34.47 sec      | 2 min 3.96 sec 
      |  5 min 44.95 sec    | 1 min 13.09 sec      | 2 min 6.48 sec

카운트 (1)

      | 6 min 49.64 sec    | 2 min 0.80 sec       | 2 min 11.64 sec
      | 6 min 31.64 sec    | 1 min 41.19 sec      | 1 min 43.51 sec

++ 이것은 캐시 파종 호출로 간주됩니다. 나머지보다 느리게 될 것으로 예상됩니다.

결과가 스스로 말하고 싶습니다. 카운트 (ID)는 일반적으로 다른 사람들을 가장 잘라냅니다. WHERE 절을 추가하면 조항이 아는 경우에도 액세스 시간이 크게 줄어 듭니다. 달콤한 지점은 계산 된 것으로 보입니다 (id) ...이 ID가 null이 아닌 곳.

나는 다른 사람들의 결과, 아마도 작은 테이블이나 계산하는 분야와 다른 분야에 대한 조항이있는 다른 사람들의 결과를보고 싶습니다. 내가 고려하지 않은 다른 변형이 있다고 확신합니다.

대안을 찾으십시오

보시다시피 테이블이 커질 때 COUNT 쿼리가 느려집니다. 가장 중요한 것은 해결하려는 문제의 본질을 고려하는 것입니다. 예를 들어 많은 개발자가 사용합니다 COUNT 결과 세트의 총 페이지 수를 결정하기 위해 큰 레코드 세트에 대한 페이지 매김을 생성 할 때 쿼리.

그것을 아는 것은 COUNT 쿼리는 느리게 커지고, 단순히 느린 쿼리를 측면에서 단계적으로 할 수있는 대안적인 페이지 매김 컨트롤을 표시하는 대체 방법을 고려할 수 있습니다. Google의 페이지 매김은 훌륭한 예입니다.

거절

특정 카운트와 일치하는 레코드 수를 절대적으로 알아야한다면, 데이터 피망의 고전적인 기술을 고려하십시오. 조회 시간에 행의 수를 계산하는 대신 레코드 삽입에 카운터를 증가시키고 레코드 삭제에서 해당 카운터를 줄이는 것을 고려하십시오.

이를 결정하기로 결정한 경우, Idempotent, Transactional Operations를 사용하여 해당 비정규 값을 동기화하십시오.

BEGIN TRANSACTION;
INSERT INTO  `group_relations` (`group_id`) VALUES (1);
UPDATE `group_relations_count` SET `count` = `count` + 1;
COMMIT;

또는 RDBMS가 지원하는 경우 데이터베이스 트리거를 사용할 수 있습니다.

아키텍처에 따라 Memcached와 같은 캐싱 레이어를 사용하여 저장, 증분 및 감소 및 감소하는 것이 합리적 일 수 있으며, 캐시 키가 누락 될 때 단순히 느린 카운트 쿼리로 떨어집니다. 변동이 많은 데이터가 있으면 전체 쓰기 전환을 줄일 수 있지만 이와 같은 경우 고려하고 싶을 것입니다. 개 파일 효과에 대한 솔루션.

MySQL ISAM 테이블에는 전체 테이블 스캔을 건너 뛰는 Count (*)에 대한 최적화가 있어야합니다.

카운트의 별표에는 모든 테이블 필드를 선택하기위한 별표가있는 베어링이 없습니다. 카운트 (*)가 카운트 (필드)보다 느리다고 말하는 것은 순수한 쓰레기입니다.

SELECT COUNT (*)가 SELECT COUNT (필드)보다 빠릅니다. RDBMS가 필드 대신 카운트에 "*"를 지정한다고 감지하면 증분 카운트를 평가할 필요가 없습니다. 카운트에 필드를 지정하는 경우 RDBMS는 항상 필드가 널 늘어나지 않거나 계산하지 않는지 평가합니다.

그러나 필드가 무효 인 경우 카운트의 필드를 지정하십시오.

카운트 (*) 사실과 신화 :

신화: "InnoDB는 카운트 (*) 쿼리를 잘 처리하지 않습니다":

대부분의 카운트 (*) 쿼리는 모든 스토리지 엔진에서 동일한 방식으로 실행됩니다. WHERE 절이있는 경우, 그렇지 않으면 InnoDB는 전체 테이블 스캔을 수행해야합니다.

사실: innodb는 where 절없이 카운트 (*) 쿼리를 최적화하지 않습니다.

기본 키와 같은 색인 된 열로 계산하는 것이 가장 좋습니다.

SELECT COUNT(`group_id`) FROM `group_relations`

Sebastian이 이미 말했듯이 실제로 달성하려는 것에 달려 있어야합니다. 즉, 의도를 명확하게 만듭니다! 만약 너라면 ~이다 행을 계산 한 다음 카운트 (*)로 이동하거나 단일 열을 계산하면 Count (열)가 이동합니다.

DB 공급 업체도 확인하는 것이 좋습니다. 내가 Informix를 사용했을 때 돌아 왔을 때, 그것은 단일 또는 뮤트 칼럼을 계산하는 것과 비교하여 1의 쿼리 계획 실행 비용이 1 인 Count (*)에 대한 최적화를 가졌으며, 이는 수치가 높아집니다.

Group_Relations에서 SELECT COUNT (1)를 시도하면 열에서 정보를 검색하지 않기 때문에 약간 빠릅니다.

Count (1)는 Count (*)보다 빠르었지만 더 이상 사실이 아닙니다. 현대 DBM이 열에 대해 알고 싶지 않다는 것을 알기에 충분히 똑똑하기 때문에 더 이상 사실이 아닙니다.

이와 같은 것들에 대해 MySQL에서 얻은 조언은 일반적으로 이와 같은 트릭을 기반으로 쿼리를 최적화하려고 시도하는 것이 장기적으로 저주가 될 수 있다는 것입니다. Optimizer의 작동 방식에 의존하는 누군가의 고성능 기술이 다음 릴리스에서 병목 현상이되는 MySQL의 역사에 대한 예가 있습니다.

묻는 질문에 답하는 쿼리를 작성하십시오. 모든 행의 카운트를 원한다면 Count (*)를 사용하십시오. 널이 아닌 열을 원한다면 COL이 NULL이 아닌 Count (col)를 사용하십시오. 적절하게 색인을 인덱싱하고 최적화를 Optimizer에 맡깁니다. 자체 쿼리 레벨 최적화를 시도하면 때때로 내장 최적화가 덜 효과적 일 수 있습니다.

즉, 최적화가 속도를 높이기 위해 쿼리에서 할 수있는 일이 있지만 Count가 그 중 하나라고 생각하지 않습니다.

편집 : 위의 답변의 통계는 흥미 롭습니다. 이 경우 옵티마이저에 실제로 일이 있는지 확실하지 않습니다. 저는 일반적으로 쿼리 레벨 최적화에 대해 이야기하고 있습니다.

나는 일반적으로 다음과 같은 쿼리를하는 것이 나쁜 생각이라는 것을 알고 있습니다.

SELECT * FROM `group_relations`

그러나 카운트를 원할 때 테이블이 변경 될 수 있지만 여전히 동일한 결과를 얻을 수 있으므로이 쿼리로 이동해야합니다.

SELECT COUNT(*) FROM `group_relations`

귀하의 질문에서 알 수 있듯이 이유는입니다 SELECT * 테이블의 변경으로 인해 코드의 변경이 필요할 수 있습니다. 그것은 적용되지 않습니다 COUNT(*). 특수한 행동을 원하시는 것은 매우 드 rare니다. SELECT COUNT('group_id') 당신에게 제공 - 일반적으로 당신은 레코드 수를 알고 싶어합니다. 그게 뭐야 COUNT(*) 사용하므로 사용하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top