2013-10-11 45 views
4

以下查询使用了连接缓冲区,我想知道是否有人可以向我解释为什么这样。只是想获得更多关于mysql和索引的理解。为什么MySQL使用连接缓冲区进行查询?

mysql> EXPLAIN SELECT events.event_topic_id, event_topic_name, event_topic_image, event_type_name,city_name FROM events 
    ->    JOIN event_topic ON event_topic.event_topic_id=events.event_topic_id 
    ->    JOIN event_type ON event_type.event_type_id = event_topic.event_type_id 
    ->    JOIN locations ON locations.location_id=events.location_id 
    ->    JOIN city ON city.city_id=locations.city_id 
    ->    WHERE event_date > NOW() 
    ->    GROUP BY events.event_topic_id, city.city_id; 
+----+-------------+-------------+--------+---------------------------------------+-----------------+---------+--------------------------------------+------+----------+----------------------------------------------+ 
| id | select_type | table  | type | possible_keys       | key    | key_len | ref         | rows | filtered | Extra          | 
+----+-------------+-------------+--------+---------------------------------------+-----------------+---------+--------------------------------------+------+----------+----------------------------------------------+ 
| 1 | SIMPLE  | city  | index | PRIMARY        | city_name  | 52  | NULL         | 6 | 100.00 | Using index; Using temporary; Using filesort | 
| 1 | SIMPLE  | locations | ref | PRIMARY,city_id      | city_id   | 1  | PremiumCONNECT.city.city_id   | 1 | 100.00 | Using index         | 
| 1 | SIMPLE  | events  | ref | location_id,event_topic_id,event_date | location_id  | 2  | PremiumCONNECT.locations.location_id | 3 | 100.00 | Using where         | 
| 1 | SIMPLE  | event_type | index | PRIMARY        | event_type_name | 52  | NULL         | 2 | 100.00 | Using index; Using join buffer    | 
| 1 | SIMPLE  | event_topic | eq_ref | PRIMARY,event_type_id     | PRIMARY   | 1  | PremiumCONNECT.events.event_topic_id | 1 | 100.00 | Using where         | 
+----+-------------+-------------+--------+---------------------------------------+-----------------+---------+--------------------------------------+------+----------+----------------------------------------------+ 

事件表:

CREATE TABLE `events` (
    `event_id` smallint(8) unsigned NOT NULL AUTO_INCREMENT, 
    `location_id` smallint(3) unsigned NOT NULL, 
    `event_date` datetime NOT NULL, 
    `event_topic_id` tinyint(3) unsigned NOT NULL, 
    PRIMARY KEY (`event_id`), 
    KEY `location_id` (`location_id`), 
    KEY `event_topic_id` (`event_topic_id`), 
    KEY `event_date` (`event_date`), 
    CONSTRAINT `events_ibfk_2` FOREIGN KEY (`event_topic_id`) REFERENCES `event_topic` (`event_topic_id`) ON DELETE CASCADE ON UPDATE CASCADE, 
    CONSTRAINT `events_ibfk_3` FOREIGN KEY (`location_id`) REFERENCES `locations` (`location_id`) ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB AUTO_INCREMENT=91 DEFAULT CHARSET=latin1 

事件主题表:

CREATE TABLE `event_topic` (
    `event_topic_id` tinyint(3) unsigned NOT NULL AUTO_INCREMENT, 
    `event_topic_name` varchar(100) DEFAULT NULL, 
    `event_topic_description` text NOT NULL, 
    `event_topic_cost` decimal(7,2) DEFAULT NULL, 
    `event_type_id` tinyint(3) unsigned NOT NULL, 
    `event_topic_clickthrough` tinytext, 
    `event_topic_length` varchar(6) NOT NULL, 
    `event_topic_image` varchar(41) DEFAULT NULL, 
    `event_topic_image_md5` char(32) NOT NULL, 
    PRIMARY KEY (`event_topic_id`), 
    KEY `event_type_id` (`event_type_id`), 
    KEY `topic_image_sha1` (`event_topic_image_md5`), 
    CONSTRAINT `event_topic_ibfk_1` FOREIGN KEY (`event_type_id`) REFERENCES `event_type` (`event_type_id`) ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=latin1 

事件类型表:

CREATE TABLE `event_type` (
    `event_type_id` tinyint(3) unsigned NOT NULL AUTO_INCREMENT, 
    `event_type_name` varchar(50) NOT NULL, 
    `conf_email` text, 
    PRIMARY KEY (`event_type_id`), 
    KEY `event_type_name` (`event_type_name`) 
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 

位置表:

CREATE TABLE `locations` (
    `location_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, 
    `location_name` varchar(50) NOT NULL, 
    `location_address` tinytext NOT NULL, 
    `location_capacity` smallint(6) NOT NULL, 
    `city_id` tinyint(3) unsigned NOT NULL, 
    `gps_coords` varchar(30) DEFAULT NULL, 
    PRIMARY KEY (`location_id`), 
    KEY `city_id` (`city_id`), 
    CONSTRAINT `locations_ibfk_1` FOREIGN KEY (`city_id`) REFERENCES `city` (`city_id`) ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=latin1 

城市表:

CREATE TABLE `city` (
    `city_id` tinyint(3) unsigned NOT NULL AUTO_INCREMENT, 
    `city_name` varchar(50) NOT NULL, 
    PRIMARY KEY (`city_id`), 
    UNIQUE KEY `city_name` (`city_name`) 
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1 
+0

http://s.petrunia.net/blog/?p=18通常使用连接缓冲区是一件好事(但也表明您的查询可能会被调整)。 –

+0

这个执行计划看起来非常愚蠢。但是对于表中给定数量的行,引擎可能会比找到一个好的执行计划更快地在所有表之间执行交叉连接。 –

回答

7

因为它说,在“http://dev.mysql.com/doc/refman/5.1/en/explain-output.html”:从早期的”表的连接被读入部分进入加入缓冲液,然后他们的行从缓冲区用于执行连接与当前表格。“

所以在你的情况下,你已经加入了event_topic,所以优化器能够使用来自连接缓冲区的event_topic内容。

使用缓冲区是一件好事;您可能注意到在EXPLAIN输出的第一行中出现了不需要的“Using temporary; Using filesort”,这可能来自GROUP BY,在这种情况下可能是不可避免的。

顺便说一下,你会遇到city_name上的“UNIQUE”约束问题吗? BTW

"STRAIGHT_JOIN" and "FORCE INDEX": 
EXPLAIN SELECT events.event_topic_id, event_topic_name, event_topic_image, event_type_name,city_name FROM events 
    ->    straight_join event_topic force index(primary) ON event_topic.event_topic_id=events.event_topic_id 
    ->    straight_join event_type force index(primary) ON event_type.event_type_id = event_topic.event_type_id 
    ->    straight_join locations force index(primary) ON locations.location_id=events.location_id 
    ->    straight_join city force index(primary) ON city.city_id=locations.city_id 
    ->    WHERE event_date > NOW() 
    ->    GROUP BY events.event_topic_id, city.city_id; 

,使用连接缓冲不好:我想斯普林菲尔德(两人在新泽西州),华盛顿,格林维尔等

+0

好的,这是有道理的。我之所以研究这个问题,是因为mysqltuner抱怨说“没有索引的联接”,我应该增加join_buffer_size或者“总是使用联接索引”。无论如何要知道需要为此查询缓冲多少信息? – JonoCoetzee

+0

W.r.t对于独特的城市来说,这个系统中的事件只会在南非的主要城市举办,所以不会有任何同名的城市。感谢您指出,虽然! – JonoCoetzee

+0

好的 - 假设你正在为美国写一个系统,我的错误。 –

1

尝试使用。这意味着您需要改进或参考正确的索引。

相关问题