我原本希望函数调用“expcious”只被调用一次,但它似乎是为“children”中的每一行调用的。是否可以将 CTE/查询调整为仅调用该函数一次,并为每个子行返回该值(所有子行都具有相同的父 id)。
“昂贵”函数只是插入到调用表中,以记录查询调用它的次数。应用于函数的确定性不会给出所需的行为。
数据库是 Amazon Aurora MySQL 8.x。
set @pParentId = 2;
WITH cte AS
(
select id, sandpit.expensive(id) as result from sandpit.parents where id = @pParentId
)
SELECT p.*, c.*, cte.result
FROM sandpit.parents p
LEFT OUTER JOIN sandpit.children c ON c.parentId = p.id
JOIN cte ON cte.id = p.id
WHERE p.id = @pParentId;
create table sandpit.parents (
id int NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
PRIMARY KEY (id)
);
insert into sandpit.parents (name) values ("A");
insert into sandpit.parents (name) values ("B");
insert into sandpit.parents (name) values ("C");
create table sandpit.children (
id int NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
parentId int NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (parentId) REFERENCES sandpit.parents(id)
);
insert into sandpit.children (parentId, name) values (1, "1");
insert into sandpit.children (parentId, name) values (2, "1");
insert into sandpit.children (parentId, name) values (2, "2");
insert into sandpit.children (parentId, name) values (2, "3");
insert into sandpit.children (parentId, name) values (2, "4");
insert into sandpit.children (parentId, name) values (2, "5");
create table sandpit.calls (
id int NOT NULL AUTO_INCREMENT,
parentId int NOT NULL,
callTime DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
我发现只需将 distinct 修饰符添加到 CTE 查询即可解决该问题。我不明白为什么这是必要的,但是这个每一个稍微修改过的查询都只能解析为对“昂贵”函数的一次调用。
id = @pParentId 的 select 语句不应多次调用,因为 pParentId 是单个常量值。
WITH cte AS
(
select distinct id, sandpit.expensive(id) as result from sandpit.parents where id = @pParentId
)
SELECT p.*, c.*, cte.result
FROM sandpit.parents p
LEFT OUTER JOIN sandpit.children c ON c.parentId = p.id
JOIN cte ON cte.id = p.id
WHERE p.id = @pParentId;