문제

속도를 높이는 방법 select count(*) ~와 함께 group by?
너무 느리고 매우 자주 사용됩니다.
사용하는 데 큰 어려움이 있습니다 select count(*) 그리고 group by 3,000,000 행 이상이있는 테이블이 있습니다.

select object_title,count(*) as hot_num   
from  relations 
where relation_title='XXXX'   
group by object_title  

relation_title, Object_title Varchar입니다.여기서 relation_title = 'xxxx', 1,000,000 행 이상을 반환하면 인덱스로 이어집니다. Object_title 잘 작동 할 수 없었습니다.

도움이 되었습니까?

해결책

어려움이 증가하기 위해 시도해 볼 몇 가지 사항이 있습니다.

(더 쉬운) - 올바른 커버링 색인이 있는지 확인하십시오

CREATE INDEX ix_temp ON relations (relation_title, object_title);

이렇게하면 기존 스키마가 주어지면 최대화가 최대화되어야합니다 (MySQL 최적화 버전의 버전이 실제로 바보가 아니라면 쿼리를 충족시키는 데 필요한 I/OS의 양을 최소화합니다 (인덱스가 전체 인덱스가있는 경우와는 달리). 스캔 해야하는 경우) 쿼리가 커버되므로 클러스터 된 인덱스를 터치하지 않아도됩니다.

(조금 더 힘들어) - Varchar 필드가 가능한 한 작다는 것을 확인하십시오.

MySQL의 Varchar Indexes와의 성능 과제 중 하나는 쿼리를 처리 할 때 필드의 전체 선언 된 크기가 RAM으로 끌려 있다는 것입니다. 따라서 Varchar (256)가 있지만 4 숯 만 사용하는 경우 쿼리가 처리되는 동안 여전히 256 바이트 RAM 사용량을 지불하고 있습니다. 아야! 따라서 Varchar 한계를 쉽게 축소 할 수 있다면 쿼리 속도가 빨라집니다.

(더 단단한) - 정규화

단일 문자열 값을 갖는 행의 30%는 다른 테이블로 정규화하기위한 분명한 외침이므로 수백만 번 문자열을 복제하지 않습니다. 세 테이블을 정규화하고 정수 ID를 사용하여 결합하는 것을 고려하십시오.

경우에 따라 현재 테이블의 이름과 일치하는 뷰로 표지 아래에서 정규화하고 정규화를 숨길 수 있습니다. 그러면 삽입/업데이트/삭제 쿼리를 정규화에 대해 알 수 있지만 선택을 내버려 둘 수 있습니다. .

(가장 하드) - 해시 끈 열을 해시하고 해시를 색인

정규화가 너무 많은 코드를 변경하는 것을 의미하지만 스키마를 약간 변경할 수 있다면 문자열 열에 128 비트 해시를 만드는 것을 고려할 수 있습니다 ( MD5 기능). 이 경우 (정규화와 달리) 모든 쿼리, 인서트 및 일부 선택 만 변경할 필요는 없습니다. 어쨌든, 당신은 당신의 스트링 필드를 해시 한 다음 해시에서 인덱스를 만들고 싶을 것입니다.

CREATE INDEX ix_temp ON relations (relation_title_hash, object_title_hash);

해시 인덱스를 통해 계산을 수행하고 클러스터 된 인덱스를 가져 오지 않도록 Select와 함께 플레이해야합니다 (쿼리를 만족시키기 위해 Object_title의 실제 텍스트 값을 해결하는 데 필요).

또한 relation_title이 varchar 크기가 작지만 객체 제목이 긴 크기를 가지고 있다면, 잠재적으로 Object_title 만 해시하고 인덱스를 만들 수 있습니다. (relation_title, object_title_hash).

이 솔루션은이 필드 중 하나 또는 둘 다 해시 크기에 비해 매우 긴 경우에만 도움이됩니다.

또한 소문자 문자열의 해시가 대문자의 해시와 동일하지 않기 때문에 해싱으로 인한 흥미로운 사례 감지/콜레이션 영향이 있습니다. 따라서 해시를 해제하기 전에 문자열에 정식화를 적용해야합니다. 다른 단어에서는 대사율 DB에있는 경우 해시 소문자 만 해시해야합니다. 또한 DB가 선행/후행 공간을 처리하는 방식에 따라 처음 또는 끝에서 공간을 다듬을 수도 있습니다.

다른 팁

복합 인덱스를 사용하여 그룹별로 그룹에 열을 색인화하는 것이 가장 먼저 시도됩니다. 이와 같은 쿼리는 인덱스 데이터 만 사용하여 잠재적으로 응답 할 수 있으며 테이블을 전혀 스캔 할 필요가 없습니다. 인덱스의 레코드가 정렬되므로 DBMS는 그룹 처리의 일부로 별도의 종류를 수행 할 필요가 없습니다. 그러나 인덱스는 테이블에 대한 업데이트 속도를 늦추므로 테이블이 많은 업데이트를 경험하면 이에주의하십시오.

테이블 스토리지에 InnoDB를 사용하는 경우 테이블의 행은 기본 키 인덱스에 의해 물리적으로 클러스터됩니다. 이 (또는 주요 부분)가 Key에 의해 그룹과 일치하는 경우, 관련 레코드가 함께 검색되기 때문에 이와 같은 쿼리 속도를 높여야합니다. 다시 말하지만, 이것은 별도의 종류를 수행하지 않아도됩니다.

일반적으로 비트 맵 인덱스는 또 다른 효과적인 대안이지만 MySQL은 현재 내가 아는 한 이들을 지원하지 않습니다.

구체화 된 견해는 또 다른 가능한 접근법이지만, 이것은 MySQL에서 직접 지원되지 않습니다. 그러나 카운트 통계가 완전히 최신 상태가되지 않으면 주기적으로 CREATE TABLE ... AS SELECT ... 결과를 수동으로 캐시하는 명령문. 투명하지 않지만 귀하의 경우에는 허용 될 수 있기 때문에 약간 추악합니다.

트리거를 사용하여 논리 수준 캐시 테이블을 유지할 수도 있습니다. 이 테이블에는 그룹 별 그룹의 각 열에 대한 열이 있으며 해당 그룹화 키 값에 대한 행 수를 저장하기위한 카운트 열이 있습니다. 기본 테이블에 행이 추가되거나 업데이트 될 때마다 해당 그룹화 키의 요약 테이블의 카운터 행을 삽입하거나 증가/감소시킵니다. 캐시 된 요약은 항상 최신 상태이며 각 업데이트는 점진적으로 수행되며 리소스 영향이 적기 때문에 가짜 구체화 된보기 접근 방식보다 우수 할 수 있습니다. 그러나 캐시 테이블에서 잠금 경합을 조심해야 할 것 같아요.

InnoDB가있는 경우 Count (*) 및 기타 집계 기능이 테이블 스캔을 수행합니다. 여기에 몇 가지 해결책이 있습니다.

  1. 트리거를 사용하고 집계를 별도의 테이블에 저장하십시오. 장점 : 무결성. 단점 : 느린 업데이트
  2. 처리 대기열을 사용하십시오. 장점 : 빠른 업데이트. 단점 : 기존 상태는 대기열이 처리 될 때까지 지속될 수 있으므로 사용자가 무결성 부족을 느낄 수 있습니다.
  3. 스토리지 액세스 계층을 완전히 분리하고 매장 집계를 별도의 테이블로 분리하십시오. 스토리지 계층은 데이터 구조를 알고 있으며 전체 카운트를 수행하는 대신 델타를 적용 할 수 있습니다. 예를 들어, 객체가 추가 된시기를 알 수 있도록 "addobject"기능을 제공하는 경우 집계에 영향을 미칩니다. 그럼 당신은 만합니다 update table set count = count + 1. 장점 : 빠른 업데이트, 무결성 (여러 클라이언트가 동일한 레코드를 변경할 수있는 경우 잠금 장치를 사용할 수 있습니다). 단점 : 당신은 약간의 비즈니스 로직과 스토리지를 연결합니다.

몇 명의 개인이 쿼리에 어떤 엔진을 사용하고 있는지 물었습니다. 나는 당신이 다음의 재선에 MyISAM을 사용하는 것이 좋습니다.

innodb - @Sorin Mocanu는 인덱스에 관계없이 전체 테이블 스캔을 수행 할 것을 올바르게 확인했습니다.

미사 - 항상 현재 행 계산을 편리하게 유지합니다.

마지막으로 @justin이 언급했듯이 적절한 커버링 색인이 있는지 확인하십시오.

CREATE INDEX ix_temp ON relations (relation_title, object_title);

테스트 카운트 (MyPrimaryIndexColumn) 및 성능을 카운트 (*) 비교

더 많은 RAM/CPUS/IO가 필요한 지점이 있습니다. 당신은 당신의 하드웨어를 위해 그것을 쳤을 것입니다.

테이블의 총 행의 1-2% 이상을 기록한 쿼리에 대해 인덱스를 사용하는 것이 일반적으로 효과적이지 않습니다. 대형 쿼리가 인덱스를 추구하고 북마크 조회를 수행하는 경우, 하루 종일 쿼리에서 온 캐시 계획 때문일 수 있습니다. 테이블 스캔을 강제하고 더 빠른지 확인하려면 (index = 0)에 추가하십시오.

이것을 가져옵니다 :http://www.microsoft.com/communities/newsgroups/en-us/default.aspx?dg=microsoft.public.sqlserver.programming&tid=4631bab4-0104-47aa-b548-e8428073b6e6&cat=&cat=&cat=> 1

전체 테이블의 크기가 있다면 메타 테이블 또는 정보 스키마를 쿼리해야합니다 (내가 알고있는 모든 DBM에 존재하지만 MySQL에 대해서는 잘 모르겠습니다). 쿼리가 선택적이면 인덱스가 있는지 확인해야합니다.

Afaik 더 이상 할 수있는 일은 없습니다.

데이터베이스에 보관할 특정 이유가 없거나 데이터를 분할하고 쿼리를 개별적으로 실행할 수없는 한 데이터를 보관하는 것이 좋습니다.

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