2010-04-02 5 views
1

위치를 우편 번호에 매핑하는 표가 하나 있습니다. 예를 들어, 뉴욕 주에는 약 2000 개의 우편 번호가 있습니다. 내가 보낸 우편 번호에 메일을 매핑하는 다른 테이블이 있지만이 테이블에는 약 500 만 개의 행이 있습니다. 나는 뉴욕 주에 보내진 모든 메일을 찾고 싶지만, 간단하지만 쿼리는 믿을 수 없을만큼 느립니다. 나는 그것이 끝날 때까지 충분히 오래 기다릴 수 없었습니다. 문제는 5 백만 행입니까? 나는 도울 수는 없지만, 요즘엔 5 백만이 그렇게 큰 숫자가되어서는 안된다고 생각합니다 ... 아, 모든 것이 색인되어 있습니다. SQL은 그러한 대규모 조인을 처리하도록 설계되지 않았습니까?MySQL에서 합류 할 수있는 적절한 수의 행과 테이블은 무엇입니까?

업데이트 : 사람들이 물어 본 것처럼이 질문을 테이블 정의와 내가 사용하고있는 쿼리로 업데이트했습니다.

-- Roughly 70,000 rows 
CREATE TABLE `mail_zip` (
    `mail_id` int(11) default NULL, 
    `zip` int(11) default NULL, 
    KEY `index_mail_zip_on_mail_id` (`mail_id`), 
    KEY `index_mail_zip_on_zip` (`zip`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 

-- Roughly 5,000,000 rows 
CREATE TABLE `geographies` (
    `city_id` int(11) default NULL, 
    `postal_code` int(11) default NULL, 
    KEY `index_geographies_on_city_id` (`city_id`), 
    KEY `index_geographies_on_postal_code` (`postal_code`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 

-- Query 
select mz.mail_id from mail_zip mz join geographies g on mz.zip = g.postal_code where g.city_id = 36 limit 10; 

업데이트 2 : 알았습니다. 거짓말했습니다. 적절한 인덱스를 사용하면 위 쿼리가 올바르게 작동합니다. 문제는 실제로 order by 절입니다. 아래의 두 개의 거의 동일한 쿼리를보십시오. 유일한 차이점은 "order by m.sent_on desc"로, 추가 4 분 30 초를 쿼리에 추가합니다! 또한, 설명을 사용하여 주문을 추가하면 느려지는 파일 경로가 사용됩니다. 그러나 sent_on은 색인이 생성되었으므로 색인을 사용하지 않는 이유는 무엇입니까? 색인을 제대로 작성하면 안됩니다.

-- Roughly 350,000 rows 
CREATE TABLE `mail` (
    `id` int(11) NOT NULL auto_increment, 
    `sent_on` datetime default NULL, 
    `title` varchar(255) default NULL, 
    PRIMARY KEY (`id`), 
    KEY `index_mail_on_sent_on` (`sent_on`), 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 

-- Runs in 0.19 seconds 
-- Query 
select distinct(m.id), m.title from mail m join mail_zip mz on mz.mail_id = m.id join geographies g on g.postal_code = mz.zip where g.city_id = 36 limit 10; 

+----+-------------+-------+--------+--------------------------------------------------------+---------+---------+----------------------+---------+-----------------------+ 
| id | select_type | table | type | possible_keys           | key  | key_len | ref     | rows | Extra     | 
+----+-------------+-------+--------+--------------------------------------------------------+---------+---------+----------------------+---------+-----------------------+ 
| 1 | SIMPLE  | mz | ALL | index_mail_zip_on_com_id,index_mail_zip_on_zip   | NULL | NULL | NULL     | 5260053 | Using temporary  | 
| 1 | SIMPLE  | m  | eq_ref | PRIMARY            | PRIMARY | 4  |   mz.com_id |  1 |      | 
| 1 | SIMPLE  | g  | ref | index_geographies_on_city_id,zip      | zip  | 5  |   mz.zip |  1 | Using where; Distinct | 
+----+-------------+-------+--------+--------------------------------------------------------+---------+---------+----------------------+---------+-----------------------+ 

-- Runs in 4 minutes and 30 seconds 
-- Query 
select distinct(m.id), m.title from mail m join mail_zip mz on mz.mail_id = m.id join geographies g on g.postal_code = mz.zip where g.city_id = 36 order by m.sent_on desc limit 10; 

+----+-------------+-------+--------+--------------------------------------------------------+---------+---------+----------------------+---------+---------------------------------+ 
| id | select_type | table | type | possible_keys           | key  | key_len | ref     | rows | Extra       | 
+----+-------------+-------+--------+--------------------------------------------------------+---------+---------+----------------------+---------+---------------------------------+ 
| 1 | SIMPLE  | mz | ALL | index_mail_zip_on_com_id,index_mail_zip_on_zip   | NULL | NULL | NULL     | 5260053 | Using temporary; Using filesort | 
| 1 | SIMPLE  | m  | eq_ref | PRIMARY            | PRIMARY | 4  |   mz.com_id |  1 |         | 
| 1 | SIMPLE  | g  | ref | index_geographies_on_city_id,zip      | zip  | 5  |   mz.zip |  1 | Using where; Distinct   | 
+----+-------------+-------+--------+--------------------------------------------------------+---------+---------+----------------------+---------+---------------------------------+ 
+2

정확한 테이블 및 인덱스 정의와 느린 쿼리에 대한 자세한 정보를 추가하십시오. –

+0

참고 : 정확한 테이블 및 인덱스 정의를 표시하려면 각 관련 테이블에 대해 '테이블 생성 이름 표시'를하고 여기에 게시하십시오. –

+0

사람들이 물어 보았 듯이이 질문을 테이블 정의와 내가 사용하고있는 쿼리로 업데이트했습니다. –

답변

5

MySQL은 완벽하게 500 만 개의 행이 포함 된 조인을 처리 할 수 ​​있습니다.

당신의 문제는 아마 두 가지 중 하나입니다 : 당신은 인덱스 누락

  • .
  • 조인 조건에서 인덱스 된 열에 sargable이 아닌 함수를 사용하는 경우와 같이 옵티마이 저가 최상의 인덱스를 사용할 수 없도록 쿼리를 작성합니다.

"모든 것이 색인되어 있습니다"라고 주장 했으므로 두 번째라고 생각합니다. 테이블 정보와 쿼리를 게시하면 문제를 해결하는 데 도움이 될 것입니다.

쿼리에서 EXPLAIN을 실행하여 사용중인 인덱스를 확인할 수도 있습니다.

+0

사람들이 물어 보았 듯이이 질문을 테이블 정의와 내가 사용하고있는 쿼리로 업데이트했습니다. –

0

최대 수백 개의 테이블을 가진 10 개의 테이블에 참여할 수 있어야하며 결과를 빨리 얻을 수 있어야합니다.

인덱싱 전략이나 쿼리 작업 또는 쿼리 계획이 있다고 가정합니다.

SQL 자체와는 아무런 관련이 없습니다. 그것은 MySQL 또는 MySQL에서 사용하는 특정 스토리지 엔진과 관련 될 수 있습니다.

SQL 표준은 인덱스와 관련된 내용을 정의하지 않는다는 것을 알고 계셨습니까? 인덱스와 관련된 모든 것이 비표준이라고 주장 할 수 있습니다. '표준에 추가'가 더 나은 방법 일 수 있습니다.

+0

사람들이 물어 보았 듯이이 질문을 테이블 정의와 내가 사용하고있는 쿼리로 업데이트했습니다. –