2012-07-04 4 views
2

나는 다음과 같은 쿼리가 :MySQL의 MIN GROUP BY (> 8000 행)

SELECT contact_purl, contact_firstName, contact_lastName, MIN(contact_id) AS MinID 
FROM contacts 
WHERE contact_client_id = 1 
GROUP BY contact_purl 
HAVING COUNT(contact_id) > 1 

목적은 "contact_purl"중복있는 모든 연락처를 찾아 첫 번째 항목을 반환하는 것입니다.

아주 이상한 문제가 있습니다. 테이블의 행 수가 8,000 개 미만인 경우 쿼리는 1 초 이내에 렌더링됩니다. 그러나 테이블에 8,000 개가 넘는 행이 있으면 쿼리 평균은 일관되게 338 초가 걸릴 것입니다. enter image description here

그리고위한 ~ 8000 행 : enter image description here

표 ...

CREATE TABLE IF NOT EXISTS `contacts` (
    `contact_id` int(11) NOT NULL AUTO_INCREMENT, 
    `contact_client_id` int(11) DEFAULT NULL, 
    `contact_sales_id` int(11) DEFAULT NULL, 
    `contact_campaign_id` int(11) DEFAULT NULL, 
    `contact_purl` varchar(100) NOT NULL, 
    `contact_purl1` varchar(50) DEFAULT NULL, 
    `contact_purl2` varchar(50) DEFAULT NULL, 
    `contact_firstName` varchar(50) NOT NULL, 
    `contact_lastName` varchar(50) NOT NULL, 
    `contact_organization` varchar(100) DEFAULT NULL, 
    `contact_url_organization` varchar(200) DEFAULT NULL, 
    `contact_position` varchar(50) DEFAULT NULL, 
    `contact_email` varchar(100) DEFAULT NULL, 
    `contact_phone` varchar(20) DEFAULT NULL, 
    `contact_fax` varchar(20) NOT NULL, 
    `contact_address1` varchar(100) DEFAULT NULL, 
    `contact_address2` varchar(100) DEFAULT NULL, 
    `contact_city` varchar(100) DEFAULT NULL, 
    `contact_state` varchar(20) DEFAULT NULL, 
    `contact_zip` varchar(10) DEFAULT NULL, 
    `contact_IP` varchar(50) DEFAULT NULL, 
    `contact_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    `contact_pw` varchar(200) NOT NULL, 
    `contact_subscribed` varchar(1) NOT NULL DEFAULT 'Y', 
    `contact_import` varchar(200) DEFAULT NULL, 
    `contacts_c_1` varchar(500) DEFAULT NULL, 
    `contacts_c_2` varchar(500) DEFAULT NULL, 
    `contacts_c_3` varchar(500) DEFAULT NULL, 
    `contacts_c_4` varchar(500) DEFAULT NULL, 
    `contacts_c_5` varchar(500) DEFAULT NULL, 
    `contacts_c_6` varchar(500) DEFAULT NULL, 
    `contacts_c_7` varchar(500) DEFAULT NULL, 
    `contacts_c_8` varchar(500) DEFAULT NULL, 
    `contacts_c_9` varchar(500) DEFAULT NULL, 
    `contacts_c_10` varchar(500) DEFAULT NULL, 
    `contacts_c_11` varchar(500) DEFAULT NULL, 
    `contacts_c_12` varchar(500) DEFAULT NULL, 
    `contacts_c_13` varchar(500) DEFAULT NULL, 
    `contacts_c_14` varchar(500) DEFAULT NULL, 
    `contacts_c_15` varchar(500) DEFAULT NULL, 
    `contacts_c_16` varchar(500) DEFAULT NULL, 
    `contacts_c_17` varchar(500) DEFAULT NULL, 
    `contacts_c_18` varchar(500) DEFAULT NULL, 
    `contacts_c_19` varchar(500) DEFAULT NULL, 
    `contacts_c_20` varchar(500) DEFAULT NULL, 
    `contacts_c_21` varchar(500) DEFAULT NULL, 
    `contacts_c_22` varchar(500) DEFAULT NULL, 
    `contacts_c_23` varchar(500) DEFAULT NULL, 
    `contacts_c_24` varchar(500) DEFAULT NULL, 
    `contacts_c_25` varchar(500) DEFAULT NULL, 
    `contacts_c_26` varchar(500) DEFAULT NULL, 
    `contacts_c_27` varchar(500) DEFAULT NULL, 
    `contacts_c_28` varchar(500) DEFAULT NULL, 
    `contacts_c_29` varchar(500) DEFAULT NULL, 
    `contacts_c_30` varchar(500) DEFAULT NULL, 
    `contacts_c_31` varchar(500) DEFAULT NULL, 
    `contacts_c_32` varchar(500) DEFAULT NULL, 
    `contacts_c_33` varchar(500) DEFAULT NULL, 
    `contacts_c_34` varchar(500) DEFAULT NULL, 
    `contacts_c_35` varchar(500) DEFAULT NULL, 
    `contacts_c_36` varchar(500) DEFAULT NULL, 
    `contacts_c_37` varchar(500) DEFAULT NULL, 
    `contacts_c_38` varchar(500) DEFAULT NULL, 
    `contacts_c_39` varchar(500) DEFAULT NULL, 
    `contacts_c_40` varchar(500) DEFAULT NULL, 
    `contacts_c_41` varchar(500) DEFAULT NULL, 
    `contacts_c_42` varchar(500) DEFAULT NULL, 
    `contacts_c_43` varchar(500) DEFAULT NULL, 
    `contacts_c_44` varchar(500) DEFAULT NULL, 
    `contacts_c_45` varchar(500) DEFAULT NULL, 
    `contacts_c_46` varchar(500) DEFAULT NULL, 
    `contacts_c_47` varchar(500) DEFAULT NULL, 
    `contacts_c_48` varchar(500) DEFAULT NULL, 
    `contacts_c_49` varchar(500) DEFAULT NULL, 
    `contacts_c_50` varchar(500) DEFAULT NULL, 
    `contacts_i_1` varchar(100) DEFAULT NULL, 
    `contacts_i_2` varchar(100) DEFAULT NULL, 
    `contacts_i_3` varchar(100) DEFAULT NULL, 
    `contacts_i_4` varchar(100) DEFAULT NULL, 
    `contacts_i_5` varchar(100) DEFAULT NULL, 
    `contacts_i_6` varchar(100) DEFAULT NULL, 
    `contacts_i_7` varchar(100) DEFAULT NULL, 
    `contacts_i_8` varchar(100) DEFAULT NULL, 
    `contacts_i_9` varchar(100) DEFAULT NULL, 
    `contacts_i_10` varchar(100) DEFAULT NULL, 
    `contacts_i_11` varchar(100) DEFAULT NULL, 
    `contacts_i_12` varchar(100) DEFAULT NULL, 
    `contacts_i_13` varchar(100) DEFAULT NULL, 
    `contacts_i_14` varchar(100) DEFAULT NULL, 
    `contacts_i_15` varchar(100) DEFAULT NULL, 
    PRIMARY KEY (`contact_id`), 
    KEY `contact_campaign_id` (`contact_campaign_id`), 
    KEY `contact_client_id` (`contact_client_id`), 
    KEY `contact_purl2` (`contact_purl2`), 
    KEY `contact_purl1` (`contact_purl1`), 
    KEY `contact_purl` (`contact_purl`) 
) 

나는 최근이 여기

는 ~ 5000 개 행이 테이블에 대한 쿼리 계획이다 테이블 최적화 및 조각 모음.

이 문제의 원인에 대한 아이디어가 있으십니까?

+2

8000 행이 "커다란"것이 아닙니다. –

+0

거기에 많은 VARCHAR (500) 열이 있습니다. 3 열 (contact_client_id, contacts_c, contact_c_number)이있는 별도의 테이블에 넣을 수 없었습니까? –

+0

'contact_firstName'과'contact_lastName'의 사용은 집계가 아니며'GROUP BY' 목록에 나타나지 않기 때문에 참 SQL이 아니라는 것에주의하십시오. 또한 인덱스를 정의 했습니까? – Neil

답변

1

먼저 테이블 구조, 쿼리 및 EXPLAIN 출력을 게시 해 주셔서 감사합니다. 난 당신이 메모리/디스크 임시 테이블 크기 경계, 따라서 큰 성능 변화를 건너고 있다고 생각합니다. contact_purl 열에 고유 한 인덱스를 넣으면 MySQL에서 중복을 삽입 할 수 없습니다. 그러면 쿼리가 필요하지 않게됩니다. 그렇지 않으면, (contact_client_id, contact_purl)에 색인을 작성하여 MySQL이 색인에서 원하는 행을 직접 알아낼 수 있도록하십시오. 열 검색을 분리하고 하위 쿼리를 사용하여 열을 검색 할 수도 있습니다. 다음과 같은 내용이있을 수 있습니다.

SELECT contact_purl, contact_firstName, contact_lastName, contact_id 
FROM contacts, (SELECT MIN(contact_id) AS MinID 
FROM contacts 
WHERE contact_client_id = 1 
GROUP BY contact_purl 
HAVING COUNT(contact_id) > 1) nodups WHERE nodups.MinID = contacts.contact_id 
+0

감사합니다. Joshua ..이 쿼리는 약간 성능이 좋지만 여전히 90 초가 걸렸습니다. 적어도 우리는 300 초를 버렸다. contact_purl이 색인되어 있지만 unique_index가 아닙니다. 당신은 메모리/디스크 경계를 언급했다. 문제를 해결하기 위해 내가 바라는 다음 장소라고 제안 해 주시겠습니까? –

+0

이 쿼리에 효과적으로 사용하려면 두 필드에 복합 인덱스가 필요합니다. 'ALTER TABLE contacts ADD INDEX (contact_client_id, contact_purl)' –

+0

복합 인덱스가 트릭입니다! Joshua에게 감사드립니다. –