0

我有以下 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)

这会产生以下解释:

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 万行,14 个表)的范围内,这部分被证明是一个巨大的瓶颈。任何意见,将不胜感激。

谢谢,

4

2 回答 2

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

请注意,您还可以通过限制要检索的列来改进请求的索引使用(尽管并非总是如此)。

于 2017-05-23T04:49:53.753 回答
0

匹配表中的LEFT JOIN所有字段。尝试使用它来INNER JOIN代替它。

于 2021-06-27T01:06:53.670 回答