From 8b9549e372a355d43f7563dfe64c923c056cd52d Mon Sep 17 00:00:00 2001 From: liugang Date: Wed, 30 Jul 2025 09:45:00 +0800 Subject: [PATCH 1/4] + [perf] Create index to improve performance. --- db/update21.7.3.sql | 5 ++++- db/zentao.sql | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/db/update21.7.3.sql b/db/update21.7.3.sql index 6d6b5490d0..84a8d4b92c 100644 --- a/db/update21.7.3.sql +++ b/db/update21.7.3.sql @@ -2,6 +2,9 @@ ALTER TABLE `zt_bug` CHANGE `injection` `injection` varchar(30) NOT NULL DEFAULT '', CHANGE `identify` `identify` varchar(30) NOT NULL DEFAULT ''; +CREATE INDEX `parent` ON `zt_story` (`parent`); +CREATE INDEX `path` ON `zt_task` (`path`(100)); + UPDATE `zt_project` SET `workflowGroup` = (SELECT `id` FROM `zt_workflowgroup` WHERE `code` = 'kanbanproduct' AND `main` = '1' LIMIT 1) WHERE `type` = 'project' AND `model` = 'kanban' AND `hasProduct` = '1'; UPDATE `zt_project` SET `workflowGroup` = (SELECT `id` FROM `zt_workflowgroup` WHERE `code` = 'kanbanproject' AND `main` = '1' LIMIT 1) WHERE `type` = 'project' AND `model` = 'kanban' AND `hasProduct` = '0'; @@ -57,4 +60,4 @@ UPDATE `zt_bug` SET `injection` = '' WHERE `injection` = '0'; UPDATE `zt_bug` SET `identify` = '' WHERE `identify` = '0'; INSERT INTO `zt_workflowaction` (`group`, `module`, `action`, `method`, `name`, `type`, `batchMode`, `extensionType`, `open`, `position`, `layout`, `show`, `order`, `buildin`, `role`, `virtual`, `conditions`, `verifications`, `hooks`, `linkages`, `js`, `css`, `toList`, `blocks`, `desc`, `status`, `vision`, `createdBy`, `createdDate`, `editedBy`, `editedDate`) VALUES -(0, 'project', 'execution', 'browse', '执行列表', 'single', 'different', 'none', 'normal', 'browse', 'normal', 'direct', 0, 1, 'buildin', 0, NULL, NULL, NULL, NULL, NULL, NULL, '', NULL, NULL, 'enable', 'rnd', 'admin', '2025-01-08 09:41:02', '', NULL); \ No newline at end of file +(0, 'project', 'execution', 'browse', '执行列表', 'single', 'different', 'none', 'normal', 'browse', 'normal', 'direct', 0, 1, 'buildin', 0, NULL, NULL, NULL, NULL, NULL, NULL, '', NULL, NULL, 'enable', 'rnd', 'admin', '2025-01-08 09:41:02', '', NULL); diff --git a/db/zentao.sql b/db/zentao.sql index 44ee0c18ea..0da7a8f647 100755 --- a/db/zentao.sql +++ b/db/zentao.sql @@ -2005,6 +2005,7 @@ CREATE TABLE IF NOT EXISTS `zt_story` ( `deleted` enum('0','1') NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +CREATE INDEX `parent` ON `zt_story` (`parent`); CREATE INDEX `product` ON `zt_story` (`product`); CREATE INDEX `root` ON `zt_story` (`root`); CREATE INDEX `status` ON `zt_story` (`status`); @@ -2138,6 +2139,7 @@ CREATE TABLE IF NOT EXISTS `zt_task` ( CREATE INDEX `execution` ON `zt_task` (`execution`); CREATE INDEX `story` ON `zt_task` (`story`); CREATE INDEX `parent` ON `zt_task` (`parent`); +CREATE INDEX `path` ON `zt_task` (`path`(100)); CREATE INDEX `assignedTo` ON `zt_task` (`assignedTo`); CREATE INDEX `order` ON `zt_task` (`order`); From df04c5e385a3c468ad3843bfc62c85ba3132593f Mon Sep 17 00:00:00 2001 From: liugang Date: Wed, 30 Jul 2025 09:45:31 +0800 Subject: [PATCH 2/4] * [perf] Use fetchByID instead of getByID to improve performance. --- module/task/control.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/task/control.php b/module/task/control.php index 40e5c60325..7676145466 100755 --- a/module/task/control.php +++ b/module/task/control.php @@ -982,7 +982,7 @@ class task extends control */ public function delete(int $executionID, int $taskID, string $from = '') { - $task = $this->task->getByID($taskID); + $task = $this->task->fetchByID($taskID); /* 如果是父任务,先删除所有子任务 */ if($task->isParent) From 3bcd9c66aa2e98202890606fbafa7bc5c8e8199f Mon Sep 17 00:00:00 2001 From: liugang Date: Wed, 30 Jul 2025 09:48:39 +0800 Subject: [PATCH 3/4] * [perf] Refactor to use index in query to improve performance. --- module/task/model.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/module/task/model.php b/module/task/model.php index d394093059..4258cf70cf 100755 --- a/module/task/model.php +++ b/module/task/model.php @@ -2101,11 +2101,16 @@ class taskModel extends model */ public function getAllChildId(int $taskID, bool $includeSelf = true): array { + if(!$taskID) return []; + + $task = $this->fetchByID($taskID); + if(!$task) return []; + return $this->dao->select('id')->from(TABLE_TASK) - ->where('path')->like("%,$taskID,%") + ->where('path')->like($task->path . '%') // 去除左侧的模糊查询以利用索引提高性能。Remove the left fuzzy query to use index to improve performance. ->andWhere('deleted')->eq(0) ->beginIF(!$includeSelf)->andWhere('id')->ne($taskID)->fi() - ->fetchPairs('id'); + ->fetchPairs(); } /** From 65dae5c975d994badf7c2d055eb39e22df19208f Mon Sep 17 00:00:00 2001 From: liugang Date: Wed, 30 Jul 2025 13:32:39 +0800 Subject: [PATCH 4/4] + [misc] Add unittest script of the taskModel::getAllChildId() method. --- module/task/test/model/getallchildid.php | 53 +++++++++++++++++++ .../test/model/yaml/getallchildid/task.yaml | 18 +++++++ 2 files changed, 71 insertions(+) create mode 100755 module/task/test/model/getallchildid.php create mode 100644 module/task/test/model/yaml/getallchildid/task.yaml diff --git a/module/task/test/model/getallchildid.php b/module/task/test/model/getallchildid.php new file mode 100755 index 0000000000..2bf2d40404 --- /dev/null +++ b/module/task/test/model/getallchildid.php @@ -0,0 +1,53 @@ +#!/usr/bin/env php +loadYaml('task')->gen(15); + +/** + +title=taskModel->getAllChildId(); +timeout=0 +cid=1 + +- 测试1:传入taskID=0,应该返回空数组 @0 +- 测试2:传入不存在的任务ID,应该返回空数组 @0 +- 测试3:传入已删除的任务ID,应该返回空数组 @0 +- 测试4:获取taskID=6的所有子任务ID(包含自己) + - 属性6 @6 + - 属性7 @7 +- 测试5:获取taskID=6的所有子任务ID(不包含自己)属性7 @7 +- 测试6:获取taskID=1的所有子任务ID(包含自己) + - 属性1 @1 + - 属性15 @15 + - 属性14 @14 +- 测试7:获取taskID=1的所有子任务ID(不包含自己) + - 属性15 @15 + - 属性14 @14 +- 测试8:获取taskID=2的所有子任务ID(包含自己) + - 属性2 @2 + - 属性9 @9 +- 测试9:获取taskID=2的所有子任务ID(不包含自己)属性9 @9 +- 测试10:获取taskID=3的所有子任务ID(包含自己) + - 属性3 @3 + - 属性13 @13 +- 测试11:获取taskID=3的所有子任务ID(不包含自己)属性13 @13 + +*/ + +$taskModel = $tester->loadModel('task'); + +r(count($taskModel->getAllChildId(0))) && p() && e(0); // 测试1:传入taskID=0,应该返回空数组 +r(count($taskModel->getAllChildId(999))) && p() && e(0); // 测试2:传入不存在的任务ID,应该返回空数组 +r(count($taskModel->getAllChildId(11))) && p() && e(0); // 测试3:传入已删除的任务ID,应该返回空数组 + +r($taskModel->getAllChildId(6, true)) && p('6,7') && e('6,7'); // 测试4:获取taskID=6的所有子任务ID(包含自己) +r($taskModel->getAllChildId(6, false)) && p('7') && e('7'); // 测试5:获取taskID=6的所有子任务ID(不包含自己) +r($taskModel->getAllChildId(1, true)) && p('1,15,14') && e('1,15,14'); // 测试6:获取taskID=1的所有子任务ID(包含自己) +r($taskModel->getAllChildId(1, false)) && p('15,14') && e('15,14'); // 测试7:获取taskID=1的所有子任务ID(不包含自己) +r($taskModel->getAllChildId(2, true)) && p('2,9') && e('2,9'); // 测试8:获取taskID=2的所有子任务ID(包含自己) +r($taskModel->getAllChildId(2, false)) && p('9') && e('9'); // 测试9:获取taskID=2的所有子任务ID(不包含自己) +r($taskModel->getAllChildId(3, true)) && p('3,13') && e('3,13'); // 测试10:获取taskID=3的所有子任务ID(包含自己) +r($taskModel->getAllChildId(3, false)) && p('13') && e('13'); // 测试11:获取taskID=3的所有子任务ID(不包含自己) \ No newline at end of file diff --git a/module/task/test/model/yaml/getallchildid/task.yaml b/module/task/test/model/yaml/getallchildid/task.yaml new file mode 100644 index 0000000000..304bf0a6ce --- /dev/null +++ b/module/task/test/model/yaml/getallchildid/task.yaml @@ -0,0 +1,18 @@ +title: zt_task +author: Gang Liu +version: "1.0" +fields: + - field: parent + range: "0{6},6,0,2,0{3},3,15,1" + - field: isParent + range: 1{3},0{2},1,0{8},1 + - field: path + fields: + - field: path1 + range: "``{6},`,6`,``,`,2`,``{3},`,3`,`,1,15`,`,1`" + - field: path2 + prefix: ',' + range: 1-15 + postfix: ',' + - field: deleted + range: 0{10},1,0{4}