テーブル構造:
CREATE TABLE IF NOT EXISTS `categories` (
`id` smallint(4) unsigned NOT NULL AUTO_INCREMENT,
`parentid` smallint(4) unsigned DEFAULT NULL,
`category` varchar(150) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `parentid` (`parentid`,`category`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=10 ;
INSERT INTO `categories` (`id`, `parentid`, `category`) VALUES
(1, NULL, 'A'),
(2, NULL, 'B'),
(3, 1, 'A.1'),
(4, 1, 'A.2'),
(5, 1, 'A.3'),
(6, 1, 'A.4'),
(7, 3, 'A.1.1'),
(8, 3, 'A.1.2'),
(9, 3, 'A.1.3');
コード、「callcategorycount」関数は、select ステートメントで使用できるように「categorycount」プロシージャを呼び出します。
DELIMITER $$
CREATE FUNCTION callcategorycount(id SMALLINT(4)) RETURNS SMALLINT(4) BEGIN
CALL categorycount(id, @categorycount);
RETURN @categorycount;
END$$
CREATE PROCEDURE categorycount(IN categoryid SMALLINT(4), OUT categorycount SMALLINT(4)) BEGIN
DROP TEMPORARY TABLE IF EXISTS results;
DROP TEMPORARY TABLE IF EXISTS temp1;
DROP TEMPORARY TABLE IF EXISTS temp2;
CREATE TEMPORARY TABLE temp1 AS
SELECT DISTINCT id, parentid FROM categories WHERE parentid = categoryid;
CREATE TEMPORARY TABLE results AS
SELECT id, parentid FROM temp1;
WHILE ( SELECT COUNT(*) FROM temp1 ) DO
CREATE TEMPORARY TABLE temp2 AS
SELECT DISTINCT id, parentid FROM categories WHERE parentid IN (SELECT id FROM temp1);
INSERT INTO results SELECT id, parentid FROM temp2;
DROP TEMPORARY TABLE IF EXISTS temp1;
CREATE TEMPORARY TABLE temp1 AS
SELECT id, parentid FROM temp2;
DROP TEMPORARY TABLE IF EXISTS temp2;
END WHILE;
SELECT COUNT(*) INTO categorycount FROM results;
DROP TEMPORARY TABLE IF EXISTS results;
DROP TEMPORARY TABLE IF EXISTS temp1;
END$$
DELIMITER ;
出力の場合 (実行時間: 1.7886 秒):
SELECT id, parentid, category, callcategorycount(id) AS subcategories FROM categories;
|id|parentid|category|subcategories
|1|NULL|A|7
|2|NULL|B|0
|3|1|A.1|3
|4|1|A.2|0
|5|1|A.3|0
|6|1|A.4|0
|7|3|A.1.1|0
|8|3|A.1.2|0
|9|3|A.1.3|0
「categorycount」手順を最適化するには?