2011-11-21 1 views
11

에 가입하지만, 난 아직도 이유를 설명 할 수 없다 가입 왼쪽 MySQL의 쿼리입니다 115ms 대 478ms. 그들은 모두 InnoDB를 사용하고 정의 된 관계가 있습니다. '합법성'테이블에는 11 개의 행이 들어 있지만 'card_legality'에는 약 200,000 개의 행이 포함됩니다.이유는, '상당히'내 내면보다 더 빨리 내가이 연구 한

CREATE TABLE `card_legality` (
    `card_id` varchar(8) NOT NULL DEFAULT '', 
    `legality_id` int(3) NOT NULL, 
    `cl_boolean` tinyint(1) NOT NULL, 
    PRIMARY KEY (`card_id`,`legality_id`), 
    KEY `legality_id` (`legality_id`), 
    CONSTRAINT `card_legality_ibfk_2` FOREIGN KEY (`legality_id`) REFERENCES `legality` (`legality_id`), 
    CONSTRAINT `card_legality_ibfk_1` FOREIGN KEY (`card_id`) REFERENCES `card` (`card_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

: 그리고 여기에 각각의 구조는

CREATE TABLE `legality` (
    `legality_id` int(3) NOT NULL AUTO_INCREMENT, 
    `l_name` varchar(16) NOT NULL DEFAULT '', 
    PRIMARY KEY (`legality_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=latin1; 

단순히 좌 - 가입 사용할 수 있지만 그것은 아주 잘 ... 어떤 생각을하시기 바랍니다하지 않는 것?

업데이트 : 요청에 따라 각각에 대한 설명 결과를 포함 시켰습니다. 나는 이전에 실행했지만, 나는 그것의 철저한 이해를 가지고 척 해달라고 ..

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE cl ALL PRIMARY NULL NULL NULL 199747 Using where 
1 SIMPLE l eq_ref PRIMARY PRIMARY 4 hexproof.co.uk.cl.legality_id 1 

을 AND, 내부 조인 :

id select_type table type possible_keys key key_len   ref       rows Extra 
1 SIMPLE l ALL PRIMARY NULL NULL NULL 11 
1 SIMPLE cl ref PRIMARY,legality_id legality_id 4 hexproof.co.uk.l.legality_id 33799 Using where 
+0

'card_id'는 선택의 여지가없는 VARCHAR입니다. – Ben

답변

9

card_id의 varchar 때문입니다. MySQL은 여기 mysql type conversion에 설명 된대로 card_id의 색인을 card_id로 사용할 수 없습니다. 중요한 부분은

문자열 열과 숫자를 비교할 때 MySQL은 값을 빠르게 검색하기 위해 열의 색인을 사용할 수 없습니다. str_col가 인덱싱 스트링 열이면 다음 문장에서 검색을 수행 할 때, 인덱스를 사용할 수 없습니다

SELECT * FROM tbl_name를 WHERE str_col = 1;

이 이유는 이 '1', '1'또는 '1a'와 같이 값 1로 변환 될 수있는 많은 다른 문자열이 있다는 것입니다.당신이

SELECT cl.`cl_boolean`, l.`l_name` 
FROM `card_legality` cl 
INNER JOIN `legality` l ON l.`legality_id` = cl.`legality_id` 
WHERE cl.`card_id` = '23155' 

SELECT cl.`cl_boolean`, l.`l_name` 
FROM `card_legality` cl 
LEFT JOIN `legality` l ON l.`legality_id` = cl.`legality_id` 
WHERE cl.`card_id` = '23155' 

에 쿼리를 변경하는 경우

당신은 속도에 큰 개선을보고도 다른이 EXPLAIN 볼 수 있습니다. 이 Using where; Using index이고 두 번째는 Using index이다

> desc id_test; 
+-------+------------+------+-----+---------+-------+ 
| Field | Type  | Null | Key | Default | Extra | 
+-------+------------+------+-----+---------+-------+ 
| id | varchar(8) | NO | PRI | NULL |  | 
+-------+------------+------+-----+---------+-------+ 
1 row in set (0.17 sec) 

> select * from id_test; 
+----+ 
| id | 
+----+ 
| 1 | 
| 2 | 
| 3 | 
| 4 | 
| 5 | 
| 6 | 
| 7 | 
| 8 | 
| 9 | 
+----+ 
9 rows in set (0.00 sec) 

> explain select * from id_test where id = 1; 
+----+-------------+---------+-------+---------------+---------+---------+------+------+--------------------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref | rows | Extra     | 
+----+-------------+---------+-------+---------------+---------+---------+------+------+--------------------------+ 
| 1 | SIMPLE  | id_test | index | PRIMARY  | PRIMARY | 10  | NULL | 9 | Using where; Using index | 
+----+-------------+---------+-------+---------------+---------+---------+------+------+--------------------------+ 
1 row in set (0.00 sec) 


> explain select * from id_test where id = '1'; 
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref | rows | Extra  | 
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------------+ 
| 1 | SIMPLE  | id_test | const | PRIMARY  | PRIMARY | 10  | const | 1 | Using index | 
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------------+ 
1 row in set (0.00 sec) 

제 경우 : 여기

이 표시 유사한 (하지만보다 쉽게) 시험이다. 또한 ref는 NULL 또는 CONST입니다. 말할 필요도없이, 두 번째 것이 더 좋습니다.

+0

aha! 훌륭한! 실제로 VARCHAR가이 쿼리를 거의 600 배 더 느리게 만들었을 때 INT가 아닌 'card_id'를 검색하면 정확합니다! 감사합니다 Andreas :) – Ben

+0

예. 안드레아스에게 감사합니다. – stefgosselin

+0

여기에 설명 된 링크가 추가되었습니다. 좋은 독서입니다. –

3

내가 그 쿼리 모두에서 EXPLAIN을 시도 할 것입니다. 각각 SELECT의 접두어를 EXPLAIN으로 붙이면됩니다. mySQL이 어떻게 쿼리를 최적화하고 실행하는지에 대한 유용한 정보를 제공합니다.

+3

토픽을 토대로 OP가 "EXPLAIN"을 사용하는 방법을 알고있는 꽤 큰 기회가 있다고 말하고 싶습니다. 어느 쪽이든 이런 종류의 정보는 당신이 그의 질문에 대답하려고 시도하지 않을 때 대답이 아니라 주석에 넣어 져야합니다. – Naatan

+0

안녕 L2G, 귀하의 의견에 감사드립니다. 나는 ** EXPLAIN ** 함수로 인내하고 내가 무엇을 찾을 수 있는지 보게 될 것이다. mysql 매뉴얼은 다소 부족하다 (또는 적어도 나에게있다). 많은 감사합니다 – Ben

0

MySql이 왼쪽 조인 (Left Joins)에 대해 더 나은 최적화를하고 있음을 확신합니다.

ETA : 빠른 스카우트 라운드와 내가 그렇게 내 시야를 유지하기 위해 구체적인 아무것도 찾을 수 없습니다 ..... 나는 그것이 때문에 VARCHAR 될 수 의심하지만

+0

감사합니다 K. 밥, 나는 비슷한 것을 읽었지만 자신과 같습니다. 증거를 찾지 못했습니다. – Ben

2

L2G, 그것은 꽤 많이 요약을 가지고 card_id에 사용 된 유형입니다.

실제로 벤치마킹/프로파일 링 quickies에 대해 this informative page을 인쇄했습니다. 빠른 불쌍한 프로파일 링 기술은 다음과 같습니다.

Time a SQL on MySQL 
Enable Profiling 
mysql> SET PROFILING = 1 
... 
RUN your SQLs 
... 
mysql> SHOW PROFILES; 

+----------+------------+-----------------------+ 
| Query_ID | Duration | Query     | 
+----------+------------+-----------------------+ 
|  1 | 0.00014600 | SELECT DATABASE()  | 
|  2 | 0.00024250 | select user from user | 
+----------+------------+-----------------------+ 
mysql> SHOW PROFILE for QUERY 2; 

+--------------------------------+----------+ 
| Status       | Duration | 
+--------------------------------+----------+ 
| starting      | 0.000034 | 
| checking query cache for query | 0.000033 | 
| checking permissions   | 0.000006 | 
| Opening tables     | 0.000011 | 
| init       | 0.000013 | 
| optimizing      | 0.000004 | 
| executing      | 0.000011 | 
| end       | 0.000004 | 
| query end      | 0.000002 | 
| freeing items     | 0.000026 | 
| logging slow query    | 0.000002 | 
| cleaning up     | 0.000003 | 
+--------------------------------+----------+ 

행운을 빈다.

+0

이것은 정말 유용한 정보입니다. stefgosselin, 감사합니다. 당신의 예후는 실제로 정확했지만 Andreas의 설명은 그것을 설명했습니다. 도와 줘서 고마워. – Ben

관련 문제