使用IN子查询时查询不使用索引

时间:2012-08-16 12:52:56

标签: mysql

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

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 个答案:

答案 0 :(得分: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;

答案 1 :(得分:0)

服务器可能正在跳过索引搜索,因为它无法确定列表中实际有多少项。我们的想法是,由于它没有对子查询中项目数量的良好估计,因此它将选择最保守的方法并进行扫描(可能)。

我建议使用JOIN重写查询:

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;