我有以下MySql表(只有845行):
CREATE TABLE `categories_nested_set` (
`lft` int(11) NOT NULL DEFAULT '0',
`rgt` int(11) DEFAULT NULL,
`id` int(11) DEFAULT NULL,
`category` varchar(128) DEFAULT NULL,
PRIMARY KEY (`lft`),
UNIQUE KEY `id` (`id`),
UNIQUE KEY `rgt` (`rgt`),
KEY `idx_lftrgtid` (`id`,`lft`,`rgt`),
KEY `idx_lft` (`lft`),
KEY `i1` (`lft`) USING BTREE,
KEY `i2` (`rgt`) USING BTREE,
KEY `i3` (`id`) USING BTREE,
CONSTRAINT `fk_categories_nested_set_id_category` FOREIGN KEY (`id`) REFERENCES `categories` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
(你可以看到我有很多索引,以防万一)。
我执行以下自连接查询:
SELECT *
FROM categories_nested_set AS H
LEFT JOIN categories_nested_set AS I ON (H.lft > I.lft)
生成以下EXPLAIN:
id,select_type,table,type,possible_keys,key,key_len,ref,rows,Extra
1,SIMPLE,H,ALL,NULL,NULL,NULL,NULL,845,NULL
1,SIMPLE,I,ALL,"PRIMARY,idx_lft,i1",NULL,NULL,NULL,845,"Range checked for each record (index map: 0x31)"
EXPLAIN会建议MySql选择不使用索引,我不明白为什么。表定义显示所有相关列都已编制索引。
在一个更大的查询(500万行,14x表)的范围内,这件作品被证明是一个巨大的瓶颈。任何建议将不胜感激。
谢谢,
答案 0 :(得分:0)
我认为您应该使用此查询:
SELECT * FROM categories_nested_set AS H , categories_nested_set AS I where (H.lft > I.lft);
这个想法不是使用JOIN,因为它强制MySql通过一次匹配一行来构造结果。
在我提出的解决方案中,交叉产品表是在没有连接的情况下构建的,因此它使InnoDB能够独立于另一个表从第一个表(H)中获取行,从而允许它批量行。然后,MySQL可以使用第二个表上的索引,因为没有从H表中建立链接。
在我的电脑上,建议的解决方案速度提高了约5倍,其中包含1000条记录。
以下是解释的结果:
EXPLAIN SELECT * FROM categories_nested_set AS H , categories_nested_set AS I where (H.lft > I.lft);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE H ALL PRIMARY,idx_lft,i1 NULL NULL NULL 921
1 SIMPLE I ALL PRIMARY,idx_lft,i1 NULL NULL NULL 921 Using where; Using join buffer
请注意,您还可以通过限制要检索的列来改进请求的索引使用(尽管并非总是如此)。
答案 1 :(得分:0)
LEFT JOIN
匹配表中的所有字段。尝试使用 INNER JOIN
而不是它。