2012-08-16 234 views
0

当有索引时,您会注意到主查询不使用school_id上的索引。如果我删除子查询并使用硬编码列表,它将使用索引。使用IN子查询时,查询不使用索引

mysql> explain SELECT year, race, CONCAT(percent,'%') as percent 
    -> FROM school_data_race_ethnicity as school_data_race_ethnicity_outer 
    -> WHERE school_id IN(
    -> SELECT field_school_id_value 
    -> FROM field_data_field_school_id 
    -> WHERE entity_id IN (SELECT entity_id 
    -> FROM field_data_field_district 
    -> WHERE field_district_nid = 
    -> (SELECT entity_id FROM field_data_field_district_id 
    -> WHERE `field_district_id_value` = 26130106 LIMIT 1)) 
    ->) ORDER BY year DESC, race; 
+----+--------------------+----------------------------------+----------------+------------------------------+-----------+---------+------+-------+-----------------------------+ 
| id | select_type  | table       | type   | possible_keys    | key  | key_len | ref | rows | Extra      | 
+----+--------------------+----------------------------------+----------------+------------------------------+-----------+---------+------+-------+-----------------------------+ 
| 1 | PRIMARY   | school_data_race_ethnicity_outer | ALL   | NULL       | NULL  | NULL | NULL | 97116 | Using where; Using filesort | 
| 2 | DEPENDENT SUBQUERY | field_data_field_school_id  | ALL   | NULL       | NULL  | NULL | NULL | 5325 | Using where     | 
| 3 | DEPENDENT SUBQUERY | field_data_field_district  | index_subquery | entity_id,field_district_nid | entity_id | 4  | func |  1 | Using where     | 
| 4 | SUBQUERY   | field_data_field_district_id  | ALL   | NULL       | NULL  | NULL | NULL | 685 | Using where     | 
+----+--------------------+----------------------------------+----------------+------------------------------+-----------+---------+------+-------+-----------------------------+ 
4 rows in set (0.00 sec) 

mysql> describe school_data_race_ethnicity 
    -> ; 
+-----------+--------------+------+-----+---------+----------------+ 
| Field  | Type   | Null | Key | Default | Extra   | 
+-----------+--------------+------+-----+---------+----------------+ 
| id  | int(11)  | NO | PRI | NULL | auto_increment | 
| school_id | varchar(255) | NO | MUL | NULL |    | 
| year  | int(11)  | NO | MUL | NULL |    | 
| race  | varchar(255) | NO |  | NULL |    | 
| percent | decimal(5,2) | NO |  | NULL |    | 
+-----------+--------------+------+-----+---------+----------------+ 
5 rows in set (0.00 sec) 

mysql> 

回答

2

使用INNER JOIN,而不是子查询与IN条款:

explain SELECT year, race, CONCAT(percent,'%') as percent 
FROM school_data_race_ethnicity a 
    INNER JOIN(
    SELECT field_school_id_value 
    FROM field_data_field_school_id b 
     INNER JOIN (SELECT entity_id 
        FROM field_data_field_district 
        WHERE field_district_nid = 
        (SELECT entity_id FROM field_data_field_district_id 
        WHERE `field_district_id_value` = 26130106 LIMIT 1)) c 
     ON b. entity_id = c.entity_id 
    ) d 
    ON a.school_id = d.field_school_id_value 
ORDER BY year DESC, race; 
0

服务器可能正在跳过索引查找,因为它无法计算列表中实际存在的项目数。这个想法是因为它没有很好地估计子查询中的项目数量,所以它会选择最保守的方法并使用扫描(可能)。

我建议使用重写查询连接来代替:

SELECT DISTINCT o.year, o.race, CONCAT(o.percent,'%') as percent 
FROM school_data_race_ethnicity as o 
INNER JOIN field_data_field_school_id s 
    ON s.field_school_id_value = o.school_id 
INNER JOIN field_data_field_district d 
    ON d.entity_id = s.entity_id 
WHERE field_district_nid = (
    SELECT entity_id 
    FROM field_data_field_district_id 
    WHERE `field_district_id_value` = 26130106 LIMIT 1)) 
ORDER BY o.year DESC, o.race;