我有如下表(删除列未用于我的例子):为什么当我使用子查询时,我的查询没有使用任何索引?
CREATE TABLE `person` (
`id` int(11) NOT NULL,
`name` varchar(1024) NOT NULL,
`sortname` varchar(1024) NOT NULL,
PRIMARY KEY (`id`),
KEY `sortname` (`sortname`(255)),
KEY `name` (`name`(255))
);
CREATE TABLE `personalias` (
`id` int(11) NOT NULL,
`person` int(11) NOT NULL,
`name` varchar(1024) NOT NULL,
PRIMARY KEY (`id`),
KEY `person` (`person`),
KEY `name` (`name`(255))
)
目前,我正在使用此查询该工程只是罚款:
select p.* from person p where name = 'John Mayer' or sortname = 'John Mayer';
mysql> explain select p.* from person p where name = 'John Mayer' or sortname = 'John Mayer';
+----+-------------+-------+-------------+---------------+---------------+---------+------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------------+---------------+---------------+---------+------+------+----------------------------------------------+
| 1 | SIMPLE | p | index_merge | name,sortname | name,sortname | 767,767 | NULL | 3 | Using sort_union(name,sortname); Using where |
+----+-------------+-------+-------------+---------------+---------------+---------+------+------+----------------------------------------------+
1 row in set (0.00 sec)
现在的我d想扩展这个查询来考虑别名。
首先,我使用连接尝试:
select p.* from person p join personalias a on p.id = a.person where p.name = 'John Mayer' or p.sortname = 'John Mayer' or a.name = 'John Mayer';
mysql> explain select p.* from person p join personalias a on p.id = a.person where p.name = 'John Mayer' or p.sortname = 'John Mayer' or a.name = 'John Mayer';
+----+-------------+-------+--------+-----------------------+---------+---------+-------------------+-------+-----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-----------------------+---------+---------+-------------------+-------+-----------------+
| 1 | SIMPLE | a | ALL | ref,name | NULL | NULL | NULL | 87401 | Using temporary |
| 1 | SIMPLE | p | eq_ref | PRIMARY,name,sortname | PRIMARY | 4 | musicbrainz.a.ref | 1 | Using where |
+----+-------------+-------+--------+-----------------------+---------+---------+-------------------+-------+-----------------+
2 rows in set (0.00 sec)
情况不妙:没有索引,87401行,使用临时。仅当使用distinct
时才会出现使用临时文件,但作为别名可能与名称相同,我无法真正摆脱它。
接下来,我试图替换子查询联接:
select p.* from person p where p.name = 'John Mayer' or p.sortname = 'John Mayer' or p.id in (select person from personalias a where a.name = 'John Mayer');
mysql> explain select p.* from person p where p.name = 'John Mayer' or p.sortname = 'John Mayer' or p.id in (select id from personalias a where a.name = 'John Mayer');
+----+--------------------+-------+----------------+------------------+--------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+----------------+------------------+--------+---------+------+--------+-------------+
| 1 | PRIMARY | p | ALL | name,sortname | NULL | NULL | NULL | 540309 | Using where |
| 2 | DEPENDENT SUBQUERY | a | index_subquery | person,name | person | 4 | func | 1 | Using where |
+----+--------------------+-------+----------------+------------------+--------+---------+------+--------+-------------+
2 rows in set (0.00 sec)
再次,这看起来很糟糕:没有索引,540309行。有趣的是,这两个查询(和select id from personalias a where a.name = 'John Mayer'
)工作得非常好。
为什么MySQL没有为我的两个查询使用任何索引?我还能做什么?目前,它最好为别名获取person.ids,并将它们静态添加到第二个查询中的(...)中。肯定有另一种方法来做到这一点与一个单一的查询。尽管如此,我目前没有想法。我能以某种方式迫使MySQL使用另一个(更好的)查询计划吗?
为什么在你的连接中没有'ON'子句? – RedFilter 2010-04-21 14:07:45
@OrbMan谢谢,它只是在解释的查询中,忘了修复它在另一个。 – sfussenegger 2010-04-21 14:13:54