我这里所说的主表是指在连接查询里MySQL以哪个表为主进行查询。比如说在LEFT JOIN查询里,一般来说左表就是主表,但这只是经验之谈,很多时候经验主义是靠不住的,为了说明问题,先来个例子,建两个演示用的表categories和posts:
CREATE TABLE IF NOT EXISTS `categories` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(15) NOT NULL,
`created` datetime NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE IF NOT EXISTS `posts` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`category_id` int(10) unsigned NOT NULL,
`title` varchar(100) NOT NULL,
`content` varchar(200) NOT NULL,
`created` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `category_id` (`category_id`)
);
先注意一下每个表的索引情况,以后会用到,记得随便插入一点测试数据,不用太多,但怎么也得两行以上,然后执行以下SQL:
EXPLAIN SELECT *
FROM posts
LEFT JOIN categories ON posts.category_id = categories.id
WHERE categories.id = ‘一个已经存在的ID’
ORDER BY posts.created DESC
结果如下所示:
table key Extra
categories PRIMARY Using filesort
posts category_id Using where
在explain的结果中,第一行表示的表就是主表,所以说在此查询里categories是主表,而在我们的经验里,LEFT JOIN查询里,左表(posts表)才应该是主表,这产生一个根本的矛盾,MySQL之所以这样处理,是因为在我们的WHERE部分,查询条件是按照categories表的字段来进行筛选的,而恰恰categories表存在合适的索引,所以在查询时把categories表作为主表更有利于缩小结果集。
那explain结果中的Using filesort又是为什么呢?这是因为主表是categories表,从表是posts表,而我们使用从表的字段去ORDER BY,这通常不是一个好选择,最好改成主表字段,如果鉴于需求所限,无法改成主表的字段,那么可以尝试添加如下索引:
ALTER TABLE `posts` ADD INDEX ( `category_id` , `created` );
再运行SQL时就不会有Using filesort了,这是因为主表categories在通过category_id连接从表posts时,可以进而通过索引直接得到排序后的posts结果。
主观上一旦搞错了主表,可能怎么调整索引都得不到高效的SQL,所以在写SQL时,比如说在写LEFT JOIN查询时,如果希望左表是主表,那么就要保证在WHERE语句里的查询条件尽可能多的使用左表字段,进而,一旦确定了主表,也最好只通过主表字段去ORDER BY。
决定学习mysql,发现博文非常不错,专注!