MySQL 이이 간단한 조인 쿼리에서 사용할 '명백한'키를 무시하는 이유는 무엇입니까?
-
03-07-2019 - |
문제
나는 간단한 쿼리라고 생각했지만 '영원히'필요가 있습니다. 나는 SQL 최적화에 좋지 않으므로 여러분에게 물어볼 수 있다고 생각했습니다.
설명과 함께 다음은 다음과 같습니다.
EXPLAIN SELECT *
FROM `firms_firmphonenumber`
INNER JOIN `firms_location` ON (
`firms_firmphonenumber`.`location_id` = `firms_location`.`id`
)
ORDER BY
`firms_location`.`name_en` ASC,
`firms_firmphonenumber`.`location_id` ASC LIMIT 100;
결과:
id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra
1, 'SIMPLE', 'firms_location', 'ALL', 'PRIMARY', '', '', '', 73030, 'Using temporary; Using filesort'
1, 'SIMPLE', 'firms_firmphonenumber', 'ref', 'firms_firmphonenumber_firm_id', 'firms_firmphonenumber_firm_id', '4', 'citiadmin.firms_location.id', 1, ''
CORMS_LOCATION의 키 :
Keyname Type Unique Packed Field Cardinality
PRIMARY BTREE Yes No id 65818
firms_location_name_en BTREE No No name_en 65818
CORMS_FIRMPHONENUMBER의 키 :
Keyname Type Unique Packed Field Cardinality
PRIMARY BTREE Yes No id 85088
firms_firmphonenumber_firm_id BTREE No No location_id 85088
MySQL이 Comporms_Location 테이블의 기본 키 사용을 거부하는 것처럼 보이지만 이유는 모르겠습니다.
모든 도움이 될 것입니다 많이 감사합니다.
솔루션이 게시 된 후 편집
변경된 순서로 :
EXPLAIN SELECT *
FROM `firms_firmphonenumber`
INNER JOIN `firms_location` ON (
`firms_firmphonenumber`.`location_id` = `firms_location`.`id`
)
ORDER BY
`firms_location`.`name_en` ASC,
`firms_location`.id ASC LIMIT 100;
#`firms_firmphonenumber`.`location_id` ASC LIMIT 100;
결과:
"id","select_type","table","type","possible_keys","key","key_len","ref","rows","Extra"
1,"SIMPLE","firms_location","index","PRIMARY","firms_location_name_en","767","",100,""
1,"SIMPLE","firms_firmphonenumber","ref","firms_firmphonenumber_firm_id","firms_firmphonenumber_firm_id","4","citiadmin.firms_location.id",1,""
왜 지금 이것을 사용하기로 결정 했습니까? MySQL은 몇 가지 이상한 선택을합니다 ... 모든 통찰력은 다시 도움이 될 것입니다 :)
Django의 세부 사항으로 편집하십시오
원래, 나는 (약식) 모델을 가지고있었습니다.
class Location(models.Model):
id = models.AutoField(primary_key=True)
name_en = models.CharField(max_length=255, db_index=True)
class Meta:
ordering = ("name_en", "id")
class FirmPhoneNumber(models.Model):
location = models.ForeignKey(Location, db_index=True)
number = PhoneNumberField(db_index=True)
class Meta:
ordering = ("location", "number")
Locaion의 클래스 메타를 변경합니다 ("name_en", )
가짜 명령을받지 않도록 쿼리를 수정했습니다.
해결책
이러한 것들은 시행 착오에 의한 경향이 있지만 comporms_firmphonenumber.location_id가 아닌 comporms_location.id에서 주문하십시오. 그것들은 같은 값이지만 MySQL은 인덱스를 선택할 수 있습니다.
다른 팁
조인을 위해 그것을 사용하고 있습니다. 그게 그게 'citiadmin.firms_location.id'
값의 가치 ref
열. 표시되지 않습니다 possible_keys
그리고 key
위치가없는 곳이없고 키를 반영하기 때문에 주문별로 주문할 수 있습니다.
쿼리 속도를 높이려면 인덱싱을 시도하십시오. name_en
.
위치가없고 결합 필드의 카디널리티가 결합 필드보다 높기 때문에 모든 것을 얻을 수 있다고 계산합니다. 결합에서 인덱스를 사용하면 속도가 높아지지 않으므로 정렬을 위해 인덱스 사용의 최적화가 줄어 듭니다.
먼저, 지정한 인덱스를 사용하도록 강제로 사용할 수 있습니다. 또한, 카디널리티가 올바르게 추정되도록 최적화를 시도하십시오. (나는 당신이 일련의 임의의 "다이브"로 추정하는 inno를 사용하고 있다고 생각합니다. 이것이 실제로 알고 있다면, 카디널리티가 왜 그렇게 보이는지 궁금합니다.)
이름 등을 색인화하지 마십시오. MySQL은 조인기 당 테이블 당 하나의 인덱스 만 사용하면 인덱스가 대량으로 올라갑니다.
얼마나 많은 데이터? 몇 줄 만 있으면 대부분의 데이터베이스는 어떤 색인이 있는지에 관계없이 테이블 스캔을 수행합니다.