I have an incredibly complex query being produced by an ORM, but here's the relevant portions for the sake of this question:
SELECT
...
FROM
`Broadcast` `t`
LEFT OUTER JOIN
`Site` `site`
ON (`t`.`site_id` = `site`.`id`)
LEFT OUTER JOIN
`Customer` `customer`
ON (`site`.`customer_id` = `customer`.`id`)
LEFT OUTER JOIN
`Domain` `domain`
ON (`customer`.`domain_id` = `domain`.`id`)
...
My fields are defined as follows:
>SHOW FIELDS FROM Broadcast;
+---------------------------+--------------------------------------+------+-----+------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------------+--------------------------------------+------+-----+------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| site_id | int(10) unsigned | NO | MUL | NULL | |
...
>SHOW FIELDS FROM Site;
+---------------------------+---------------------+------+-----+------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------------+---------------------+------+-----+------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| customer_id | int(11) | NO | MUL | 0 | |
...
>SHOW FIELDS FROM Customer;
+---------------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------------+------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| domain_id | int(10) unsigned | NO | MUL | 1 | |
...
>SHOW FIELDS FROM Domain;
+---------------------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
...
Why some of our IDs are int(11)
and others are int(10) unsigned
is just a matter of historical context. What's important is that the X_id
foreign key always shares a type with the relevant id
column. We never attempt to link an int(11)
with an int(10) unsigned
. Also the id
field is always the primary key for the table.
We also have indexes on all of the foreign keys:
>SHOW INDEXES FROM Broadcast;
+-----------+------------+---------------------------------------+--------------+---------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+---------------------------------------+--------------+---------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Broadcast | 0 | PRIMARY | 1 | id | A | 139708 | NULL | NULL | | BTREE | | |
| Broadcast | 1 | site_id | 1 | site_id | A | 1060 | NULL | NULL | | BTREE | | |
...
>SHOW INDEXES FROM Site;
+-------+------------+----------------------------------+--------------+---------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------------------------------+--------------+---------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Site | 0 | PRIMARY | 1 | id | A | 1876 | NULL | NULL | | BTREE | | |
| Site | 1 | customer_id | 1 | customer_id | A | 250 | NULL | NULL | | BTREE | | |
...
>SHOW INDEXES FROM Customer;
+----------+------------+--------------------------------------+--------------+---------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------+------------+--------------------------------------+--------------+---------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Customer | 0 | PRIMARY | 1 | id | A | 292 | NULL | NULL | | BTREE | | |
| Customer | 1 | domain_id | 1 | domain_id | A | 2 | NULL | NULL | | BTREE | | |
...
>SHOW INDEXES FROM Domain;
+--------+------------+-------------------------------------------+--------------+---------------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+--------+------------+-------------------------------------------+--------------+---------------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Domain | 0 | PRIMARY | 1 | id | A | 2 | NULL | NULL | | BTREE | | |
...
Each of these indexes consists of a single field, so the field is the first sequence in the index.
When I run EXPLAIN ...
on my query, the output I get looks as follows:
Site and Customer are joined with the eq_ref
type, but Domain is joined with ALL
type. Why is MySQL not using my index?
I can force MySQL to use my index by adding USE INDEX FOR JOIN (domain_id)
after the Customer table name, but this causes a new issue:
The problem just moves up from the Customer->Domain
relation to the Site->Customer
relation. I can shift the problem up one further using USE INDEX FOR JOIN (customer_id)
after the Site table name, and as you might expect this just causes the Site table to join with the ALL
type instead of eq_ref
I can't for the life of me figure out why MySQL is refusing to use my indexes
Per @ysth in the comments:
MySQL will not use an index if the table you are joining has very few rows, as the overhead of reading an index from disk exceeds the benefits