tags:

views:

110

answers:

1

In the following example, MySQL fails to use to find a ref for the JOIN clause (or so it appears). Can anyone explain why?

mysql> explain SELECT 1
 FROM `businesses` 
INNER JOIN `categories` 
ON (`businesses`.`id` = `categories`.`business_id`) 
WHERE (`categories`.`category_id` IN (1321, 7304, 9189, 4736, 4737, 1322, 8554, 1323, 1324, 9459, 1325, 1326, 4738, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 8031, 8387) 
AND `businesses`.`id` <= 170261 
 AND `businesses`.`id` >= 160262 ) ;


| id | select_type | table      | type  | possible_keys            | key         | key_len | ref  | rows  | Extra                     
+----+-------------+-------------------------------------+-------+--------------------------+-------------+---------+------+-------+-
|  1 | SIMPLE      | businesses | range | PRIMARY                  | PRIMARY     | 4       | NULL | 20492 | Using where             
|  1 | SIMPLE      | categories | range | business_id,idx_category | business_id | 10      | NULL | 20584 | Using where; Using index 
+----+-------------+-------------------------------------+-------+--------------------------+-------------+---------+------+-------+-

categories table:

| categories | CREATE TABLE `categories` (
  `id` int(11) NOT NULL auto_increment,
  `business_id` int(10) unsigned default NULL,
  `category_id` int(10) unsigned default NULL,
  `country_id` char(2) default NULL,
  `state_id` int(10) unsigned default NULL,
  `city_id` int(10) unsigned default NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `business_id` (`business_id`,`category_id`),
  KEY `idx_category2` (`country_id`,`state_id`,`city_id`,`category_id`),
  KEY `idx_category` (`category_id`)
) ENGINE=InnoDB AUTO_INCREMENT=13155275 DEFAULT CHARSET=latin1 |

Index info on categories:

+-------------------------------------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table      | Non_unique | Key_name      | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------------------------------------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| categories |          0 | PRIMARY       |            1 | id          | A         |    13154781 |     NULL | NULL   |      | BTREE      |         | 
| categories |          0 | business_id   |            1 | business_id | A         |    13154781 |     NULL | NULL   | YES  | BTREE      |         | 
| categories |          0 | business_id   |            2 | category_id | A         |    13154781 |     NULL | NULL   | YES  | BTREE      |         | 
| categories |          1 | idx_category2 |            1 | country_id  | A         |          17 |     NULL | NULL   | YES  | BTREE      |         | 
| categories |          1 | idx_category2 |            2 | state_id    | A         |          17 |     NULL | NULL   | YES  | BTREE      |         | 
| categories |          1 | idx_category2 |            3 | city_id     | A         |       53913 |     NULL | NULL   | YES  | BTREE      |         | 
| categories |          1 | idx_category2 |            4 | category_id | A         |    13154781 |     NULL | NULL   | YES  | BTREE      |         | 
| categories |          1 | idx_category  |            1 | category_id | A         |       51995 |     NULL | NULL   | YES  | BTREE      |         | 
+-------------------------------------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
A: 

Maybe it's because you're not looking for all categories with that business_id, but further limit the categories like;

WHERE (`categories`.`category_id` IN (1321, 7304, 9189, etc)

The MySQL guide has an article on the range join type that might be relevant.

Andomar
You are correct that wrapping this entire statement as a subquery, and then filtering that result set on the category_id does indeed provide a needed improvement. It's not the solution I'd like, but it's definitely usable.
David Cramer