【问题标题】:How to optimize slow Modified Preorder Tree Traversal query如何优化慢速修改前序树遍历查询
【发布时间】:2015-11-30 19:34:59
【问题描述】:

我有一个包含 82117 条记录的修改前序树遍历 (MPTT) 表。这个mysql表包含一些地理数据(国家、州、地区、城市...)

CREATE TABLE IF NOT EXISTS `geotree` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `geo_id` int(11) DEFAULT NULL,
  `name` varchar(80) COLLATE utf8_unicode_ci NOT NULL,
  `lft` int(11) NOT NULL,
  `rgt` int(11) NOT NULL,
  `parent` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `name` (`name`,`lft`,`rgt`),
  KEY `geo_id` (`geo_id`),
  KEY `parent` (`parent`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=82174 ;

当我尝试使用这样的标准 MPTT 查询获取路径时出现问题:

SELECT p.name 
FROM `geotree` AS node, `geotree` AS p 
WHERE node.lft BETWEEN p.lft AND p.rgt AND node.rgt='$value'
ORDER BY p.lft

完成需要超过 2.5 秒。有什么问题?我错过了任何索引?这种数据结构的行太多?还是查询有错误?

注意:我注意到如果我从查询中删除“ORDER BY”,查询时间会减少到 0.05 秒。

【问题讨论】:

  • 不幸的是,在 MySQL 连接中,不能在范围条件下使用索引 (BETWEEN,<,>,...)。在这种情况下,运行时间与 * 成正比。

标签: mysql data-structures mptt


【解决方案1】:

您至少应该将您的查询转换为必须带来一些性能的正确JOIN

http://sqlfiddle.com/#!9/b4d7f8/3

SELECT p.name 
FROM `geotree` AS node
INNER JOIN `geotree` AS p 
ON node.lft BETWEEN p.lft AND p.rgt 
WHERE node.rgt='$value'

由于您需要node.rgt='$value' 作为过滤器,我将添加索引KEY rgt (rgt)

【讨论】:

  • 对于这个查询,我必须添加“ORDER BY p.lft”以获得正确的顺序。一旦我这样做,它需要 2.4 秒,快一点,但还不够。添加“KEY rgt(rgt)”后同样需要0.25秒,非常接近预期的性能,但仍然不够(为此+1!)。
  • 这与OP的原始查询完全相同。为什么你认为它会有不同的表现?
猜你喜欢
  • 2011-10-17
  • 1970-01-01
  • 2013-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-14
  • 2012-04-13
相关资源
最近更新 更多