MySql query not using composite indices
I have matching Btree indices on 2 tables, but the explain plan says the engine is doing a full scan on one of the tab开发者_如何学Cles and it is very slow. When deployed both will start with ~750,000 rows, the relationship is em_localitems:em_submenuitemassoc => 1:n. My understanding is that the indices below with ** should work well in the query below as they are used left to right.
CREATE TABLE IF NOT EXISTS em_localitems (
localitemid int(11) NOT NULL AUTO_INCREMENT,
profitcenterid int(11) DEFAULT NULL,
productid int(11) DEFAULT NULL,
PRIMARY KEY (localitemid),
UNIQUE KEY locationid (profitcenterid,productid),
**KEY productid_2 (productid,profitcenterid)**
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
CREATE TABLE IF NOT EXISTS em_submenuitemassoc (
submenuitemassocid int(11) NOT NULL AUTO_INCREMENT,
productid int(11) NOT NULL,
profitcenterid int(11) NOT NULL DEFAULT '0',
submenuid int(11) NOT NULL,
enddate datetime DEFAULT NULL,
PRIMARY KEY (submenuitemassocid),
UNIQUE KEY productid (productid,profitcenterid,submenuid),
**KEY productid_3 (productid,profitcenterid,submenuid)**
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
This is the query:
SELECT * from
em_submenuitemassoc sm
LEFT outer JOIN em_localitems li2 on li2.productid=sm.productid
and li2.profitcenterid=sm.profitcenterid
and sm.profitcenterid is not null
I also tried index hinting:
SELECT * from
em_submenuitemassoc sm **use index(productid_3)**
LEFT outer JOIN em_localitems li2 on li2.productid=sm.productid
and li2.profitcenterid=sm.profitcenterid
and sm.profitcenterid is not null
"show index from em_submenuitemassoc;" returns this:
+---------------------+------------+----------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+---------------------+------------+----------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+
| em_submenuitemassoc | 1 | productid_3 | 1 | productid | A | 1136 | NULL | NULL | | BTREE | |
| em_submenuitemassoc | 1 | productid_3 | 2 | profitcenterid | A | 1136 | NULL | NULL | | BTREE | |
| em_submenuitemassoc | 1 | productid_3 | 3 | submenuid | A | 1136 | NULL | NULL | | BTREE | |
+---------------------+------------+----------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+
This is the explain plan:
+----+-------------+-------+------+------------------------+-------------+---------+--------------------------------------------------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+------------------------+-------------+---------+--------------------------------------------------+------+-------+
| 1 | SIMPLE | sm | ALL | NULL | NULL | NULL | NULL | 1136 | |
| 1 | SIMPLE | li2 | ref | locationid,productid_2 | productid_2 | 10 | datatest.sm.profitcenterid,datatest.sm.productid | 1 | |
+----+-------------+-------+------+------------------------+-------------+---------+--------------------------------------------------+------+-------+
What's so horribly wrong with this?
See that your query acces type
for table sm is "ALL". The optimizer knows it has to read all the rows of sm regardless of the join conditions.
This is probably because you're using LEFT OUTER JOIN
which returns all the rows of the left table in the join, regardless of whether there are matching rows in the right table of the join.
You're also using SELECT *
so it'll have to fetch all the columns of sm anyway. If the query required only the columns in the index, it would be able to skip reading the base table.
So there's no benefit in this query to using the index, and MySQL gains more efficiency by skipping reading the index.
精彩评论