我有一个看起来像这样的表:
类别
当我运行这样的查询时, 需要将近1秒 :
SELECT node.category_id AS node_category_id,
node.category_seo_friendly_url,
node.name,
( COUNT(parent.category_id) - ( sub_tree.depth + 1 ) ) AS depth
FROM category AS node,
category AS parent,
category AS sub_parent,
(SELECT node.category_id,
( COUNT(parent.category_id) - 1 ) AS depth
FROM category AS node,
category AS parent
WHERE node.left_id BETWEEN parent.left_id AND parent.right_id
AND node.category_id = 2
GROUP BY node.category_id
ORDER BY node.left_id)AS sub_tree
WHERE node.left_id BETWEEN parent.left_id AND parent.right_id
AND node.left_id BETWEEN sub_parent.left_id AND sub_parent.right_id
AND sub_parent.category_id = sub_tree.category_id
GROUP BY node.category_id
HAVING depth > 0
AND depth <= 1
ORDER BY node.name ASC
当我执行EXPLAIN
时,我得到以下内容:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> system NULL NULL NULL NULL 1 Using temporary; Using filesort
1 PRIMARY sub_parent const PRIMARY,category_id,left_id,right_id PRIMARY 4 const 1
1 PRIMARY node ALL left_id NULL NULL NULL 748 Using where
1 PRIMARY parent ALL left_id,right_id NULL NULL NULL 748 Range checked for each record (index map: 0x30)
2 DERIVED node const PRIMARY,category_id,left_id PRIMARY 4 1
2 DERIVED parent range left_id,right_id left_id 5 NULL 17 Using where
知道发生了什么事吗? 我承受不起这个近1秒的执行时间。
更新
-- phpMyAdmin SQL Dump
-- version 3.3.9
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: Feb 16, 2011 at 10:58 PM
-- Server version: 5.0.91
-- PHP Version: 5.2.6
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
--
-- Database: `foobar`
--
-- --------------------------------------------------------
--
-- Table structure for table `category`
--
CREATE TABLE IF NOT EXISTS `category`
(
`category_id` INT(11) NOT NULL AUTO_INCREMENT,
`name` CHAR(255) DEFAULT NULL,
`category_seo_friendly_url` CHAR(255) DEFAULT NULL,
`left_id` INT(11) DEFAULT '1',
`right_id` INT(11) DEFAULT '2',
PRIMARY KEY (`category_id`),
UNIQUE KEY `seo_friendly_url_UNIQUE` (`category_seo_friendly_url`),
KEY `category_id` (`category_id`),
KEY `left_id` (`left_id`),
KEY `right_id` (`right_id`)
)
ENGINE=MyISAM
DEFAULT CHARSET=latin1
AUTO_INCREMENT=765;
答案 0 :(得分:0)
IME,MySQL在优化子查询方面做得不好 - 特别是它似乎没有管理推式谓词。
我对查询实际上要返回的内容有点疑惑 - 尤其是“子父”
通过将left_id和right_id放入单个索引中,您可以获得一些改进。
虽然您也可以通过将查询展开到存储过程中来获得一些改进,但是假设您似乎每次都遍历几乎整个数据集,那么更好的解决方案是将树深度非规范化并将其存储为属性每个节点。事实上,你似乎只在外部查询中至少遍历过两次。
但是我注意到在查询结束时:
HAVING depth > 0
AND depth <= 1
这与
完全相同HAVING depth=1
然后提供了一种非常不同的优化查询的方法(首先获取right = left + 1的所有节点,找到没有子节点的节点,然后开始检查类别ID)。