2012-09-12 55 views
0

家伙试图总结我的头周围MySQL查询为什么它扫描表中的所有行MySQL查询扫描所有行

我有2个表topic_entry和topic_user

CREATE TABLE `topic_entry` (
    `entry_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
    `topic_id` bigint(20) unsigned NOT NULL, 
    `entry_created` datetime NOT NULL, 
    `entry_object` text, 
    `level` tinyint(4) NOT NULL DEFAULT '3', 
    PRIMARY KEY (`entry_id`), 
    KEY `entry_created` (`entry_created`), 
    KEY `level` (`level`), 
    KEY `topic_id_2` (`topic_id`,`entry_id`) 
) ENGINE=MyISAM; 

CREATE TABLE `topic_user` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
    `topic_id` bigint(20) unsigned NOT NULL, 
    `user_id` varchar(100) NOT NULL, 
    `private` enum('y','n') DEFAULT NULL, 
    `freq` enum('a','d','w') DEFAULT NULL, 
    `topic_id_freq` varchar(10) DEFAULT NULL, 
    `casematch` enum('0','1') DEFAULT '0', 
    `textmatch` enum('0','1') DEFAULT '0', 
    `topic_name_case` varchar(100) DEFAULT '', 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `topic_id_user_id` (`topic_id`,`user_id`), 
    KEY `user_id` (`user_id`), 
    KEY `topic_id_freq` (`topic_id_freq`) 
) ENGINE=MyISAM; 

这是查询我我试图运行

explain 
select te.topic_id,te.entry_id 
from topic_entry te 
WHERE te.topic_id in (select topic_id 
         from topic_user where user_id ='xyz') 
    AND te.level=4 
    AND te.entry_id > 0 
ORDER BY te.entry_id DESC 
LIMIT 5; 

解释输出表明,它扫描所有的行

| 1 | PRIMARY| te | range | PRIMARY,level | PRIMARY | 8 | NULL| **722978** | Using where    | 
| 2 | DEPENDENT SUBQUERY | topic_user | unique_subquery | topic_id_user_id,user_id | topic_id_user_id | 310  | func,const |  1 | Using index; Using where | 
+0

任何指针,以扫描如何避免 – user1590071

+0

它扫描到满足where条件结合起来。您可能需要在user_id和level和entry_id上创建一些索引作为开始,以查看它是否会执行索引扫描而不是顺序扫描。 – 2012-09-12 16:13:14

回答

3

试试这个:

EXPLAIN 
SELECT  te.topic_id,te.entry_id 
FROM  topic_entry te 
JOIN  topic_user tu ON te.topic_id = tu.topic_id AND tu.user_id = 'xyz' 
WHERE  te.level=4 
AND   te.entry_id > 0 
ORDER BY te.entry_id DESC 
LIMIT 5; 
+0

尝试加入之前,与此加入它临时filesort,这也是缓慢 – user1590071

+0

好吧,只是认为它可能有所帮助,我创建了一个测试模式,并使用您的代码创建相同的表,但没有数据,无法准确测试在我的结束查询。 –

+1

问题可能是您在这两个表中都有一个由两列组成的键,且没有设置外键关系。 –

0

试着改变你的WHERE子句中键的顺序:
WHERE te.topic_id in (select topic_id from topic_user where user_id ='xyz') AND te.level=4 AND te.entry_id > 0

WHERE te.topic_id in (select topic_id from topic_user where user_id ='xyz') AND te.entry_id > 0 AND te.level=4
我不是100%肯定(我不能测试它那一刻),但它可能会有所帮助。
原因是MySQL尝试并且无法将您的密钥映射到
topic_id, level, entry_idKEY topic_id_2,并且因额外字段而失败。

P.S.和“狡猾Raskal”有更好的解决方案,或者你可以尝试这两种

+0

在更改键序列方面没有区别。不确定,但可能是预处理器处理序列。 – user1590071

0

什么

explain extended 
select te.topic_id,te.entry_id 
from topic_entry te LEFT JOIN topic_user tu ON 
    te.topic_id = tu.topic_id AND tu.user_id = 'xyz' 
WHERE 1 = 1 
    AND te.level=4 
    AND te.entry_id > 0 
ORDER BY te.entry_id DESC 
LIMIT 5; 
+0

当使用上述查询 – user1590071

+0

@ user1590071时,您所扫描行数的差异小于1%,您没有参考约束(由于myisam),而且我也没有您的数据。不同于你的东西。 – rkosegi