2013-06-28 7 views
1

매우 느린 다음 SQL 문이 있습니다. 그것은 600-800ms에서 다릅니다!GROUP BY 대신 SQL 호출 최적화

내가 최적화 할 수있는 방법을 찾고 있지만 정확한 경로를 정확히 모르겠습니다. 내 데이터베이스는 상당히 커서. entries 테이블에는 400,000 개의 행이 있고 devices 테이블에는 90,000 개의 행이 있습니다.


SQL 문 제가 가난 하드웨어에서 그것을 실행하는거야 때문에

SELECT devices.manufacturer, COUNT(devices.manufacturer) AS device_count 
FROM entries 
    JOIN devices ON entries.device_id=devices.id 
WHERE waypoint_id IN (1,2,3,5) 
    AND entries.updated_at >= '2013-06-20 21:01:40 -0400' 
    AND entries.updated_at <= '2013-06-27 21:01:40 -0400' 
    GROUP BY devices.manufacturer; 

이 SQL 문 느린 경우, 또는 문이 나쁜이기 때문에, 또는 내가 제대로 테이블을 구성하지 않은 ? 어떤 생각이라도 감사 할 것입니다!

문의


목표는 모든 장치 제조 업체의 목록 및 해당 제조업체는 항목 테이블에 나타났다 횟수의 연결 수를 가져옵니다.


테이블 구조

장치

id int(11) NOT NULL AUTO_INCREMENT, 
mac_address varchar(255) DEFAULT NULL, 
user_id int(11) DEFAULT NULL, 
created_at datetime NOT NULL, 
updated_at datetime NOT NULL, 
manufacturer varchar(255) DEFAULT NULL, 
PRIMARY KEY (id), 
UNIQUE KEY mac_address (mac_address), 
KEY manufacturer (manufacturer) 
ENGINE=InnoDB AUTO_INCREMENT=839310 DEFAULT CHARSET=utf8; 

항목

id int(11) NOT NULL AUTO_INCREMENT, 
device_id int(11) DEFAULT NULL, 
created_at datetime NOT NULL, 
updated_at datetime NOT NULL, 
waypoint_id int(11) DEFAULT NULL, 
unsure tinyint(1) DEFAULT '0', 
PRIMARY KEY (id), 
KEY device_index (device_id) 
ENGINE=InnoDB AUTO_INCREMENT=3389538 DEFAULT CHARSET=utf8; 
,

기타 - 대체 데이터베이스를 조사했습니다. 이 데이터베이스가 미래에 매우 빠른 읽기/쓰기가 필요하다고 생각할 때, Redis는 사용의 대상이 될 것입니까?

+0

테이블에 어떤 색인이 있습니까? –

+0

엔트리 테이블에서 ID에 대한 PK와 device_id에 대한 인덱스가 있습니다. 장치 테이블에서 ID가 PK이고 제조업체 ID가 mac_address –

+2

인 경우 600-800ms가 느립니까? 내가 뭔가 빠진거야? –

답변

2

entries(waypoint_id, updated_at)에 다중 열 인덱스를 추가하면 쿼리가 더 빨리 실행됩니다.

또한, 쿼리 더 나은 같을 것이다 :

SELECT 
    devices.manufacturer, 
    COUNT(devices.manufacturer) AS device_count 
FROM 
    entries 
JOIN 
    devices ON devices.id = entries.device_id 
WHERE 
    entries.waypoint_id IN (1,2,3,5) 
AND 
    entries.updated_at BETWEEN '2013-06-20 21:01:40 -0400' AND '2013-06-27 21:01:40 -0400' 
GROUP BY 
    devices.device_id 

P.S :이 명시 적으로 외래 키로 device_id를 선언 할 수있는 좋은 일이되지 않을 것?

+0

@BrianW.BTW, 이것은 MySQL뿐만 아니라 모든 DBMS에서 마찬가지입니다. –

+1

@BrianW 아니요, 두 개의 인덱스와 같지 않습니다. 멀티 파트는 히트의 접두어와 일치해야합니다. 따라서 색인이 "A, B"에 있으면 "B"를 검색하려는 경우 일반적으로 사용하지 않습니다. 멀티 파트 인덱스를 사용하면 테이블로 이동하는 것을 신경 쓰지 않고도 인덱스 스캔에서 모든 정보를 얻을 수 있습니다. 그러나 'waypoint_id'의 카디널리티가 낮 으면이 기능을 사용할 수 없습니다. – Glenn

+0

감사합니다. 다중 열 인덱스에 대해 읽었습니다. 미래에 대해 잘 알고 있습니다. 또한 색인을 추가 한 후 시간이 ~ 650에서 ~ 420으로 떨어졌습니다. –

1

Entries {waypoint_id, updated_at}에 대한 색인이 필요합니다. 이것은을 만족해야합니다

WHERE waypoint_id IN (1,2,3,5) 
    AND entries.updated_at >= '2013-06-20 21:01:40 -0400' 
    AND entries.updated_at <= '2013-06-27 21:01:40 -0400'; 

실제 카디널리티에 따라, 또는이 지수의 필드의 순서를 반대로 할 수도 있고 그렇지 않을 수도 있습니다.

또는 Entries 테이블에 전혀 액세스하지 않으려면 Entries {waypoint_id, updated_at, device_id}covering 색인을 생성하십시오.


이 외에도 Devices {id, manufacturer}에 색인을 생성하는 것이 좋습니다. 바라건대, MySQL은 Devices 테이블에 액세스조차하지 않고 JOIN과 aggregation을 만족시키기에 충분히 똑똑 할 것이다.