我在 MySQL 存储过程中实现了 Warshall 算法。不幸的是,该过程需要很长时间才能完成。我是编写存储过程的初学者,你知道我能做些什么来让它更快吗?
简要说明:我正在尝试计算邻接表的传递闭包。我想知道,连接了哪些节点(直接在一条边上,或间接在更多边上)。例如:
Input: (1, 2), (2, 3), (3, 4)
Output: (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)
下图说明了图表:
图片来自维基共享资源:
https ://en.wikipedia.org/wiki/File:Transitive-closure.svg
您可以在SQL Fiddle或此处查看代码:
# "Warshall's algorithm" to calculate the transitive closure
# (1) For k = 1 to n
# (2) For i = 1 to n
# (3) If d[i,k] = 1
# (4) For j = 1 to n
# (5) If d[k,j] = 1 : d[i,j] = 1
create procedure closure()
begin
drop table if exists adjMatrix;
drop table if exists idArray;
create temporary table adjMatrix (idFrom int not null, idTo int not null,
primary key (idFrom, idTo));
create temporary table idArray (id int);
insert into adjMatrix select parent_id, id
from article where parent_id is not null;
insert into idArray select id from article;
blockk: begin
declare k, fink int;
declare ck cursor for select id from idArray;
declare continue handler for not found set fink = 1;
open ck;
loopk: loop
fetch ck into k;
if fink = 1 then
leave loopk;
end if;
blocki: begin
declare i, fini int;
declare ci cursor for select id from idArray;
declare continue handler for not found set fini = 1;
-- select k from dual;
open ci;
loopi: loop
fetch ci into i;
if fini = 1 then
leave loopi;
end if;
blockj: begin
if exists (select * from adjMatrix where idFrom=i and idTo=k)
then
blockx: begin
declare j, finj int;
declare cj cursor for select id from idArray;
declare continue handler for not found set finj = 1;
open cj;
loopj: loop
fetch cj into j;
if finj = 1 then
leave loopj;
end if;
if exists (select * from adjMatrix
where idFrom=k and idTo=j) then
insert into adjMatrix values (i, j);
end if;
end loop loopj;
close cj;
end blockx;
end if;
end blockj;
end loop loopi;
close ci;
-- select idFrom, idTo from adjMatrix order by idFrom, idTo;
end blocki;
end loop loopk;
close ck;
end blockk;
insert into adjMatrix select id, id from article where parent_id is null;
select idFrom, idTo from adjMatrix order by idFrom, idTo;
drop temporary table adjMatrix;
drop temporary table idArray;
end//
在我的计算机上运行具有 1466 条记录的表需要 45 秒:
mysql> call closure;
+--------+------+
| idFrom | idTo |
+--------+------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 1 | 5 |
| 2 | 3 |
| 2 | 4 |
| 2 | 5 |
| 3 | 4 |
| 3 | 5 |
| 4 | 5 |
~ ~ ~
| 1587 | 1587 |
| 1588 | 1588 |
| 1589 | 1589 |
+--------+------+
1472 rows in set (45.58 sec)