我们有这个MySQL SP,它调用一个嵌套的SP。它似乎在负载下表现不佳。
这个SP可能在加载时变慢,因为它调用嵌套的SP并使用临时表将数据传递给主SP?
DELIMITER $$
drop procedure if exists `GeoAreaFlattened_Select`;
create procedure `GeoAreaFlattened_Select`(
_areas MEDIUMTEXT,
_comparisonGroup varchar(21844),
_parentArea varchar(21844),
_areaType varchar(21844)
)
begin
drop temporary table if exists areas;
-- areas
call CreateAreas(_areas, _comparisonGroup, _parentArea, _areaType);
SELECT
areas.ID,
areas.Code,
areas.Name,
areas.LevelId,
GeoAreaLevel.Name AS AreaTypeLabel,
GeoAreaLevel.Identifier AS AreaTypeIdentifier
FROM
areas
INNER JOIN
GeoAreaLevel
ON
areas.levelid = GeoAreaLevel.id
ORDER BY areas.name ASC;
drop temporary table areas;
end
嵌套SP:
-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
drop procedure if exists `CreateAreas`;
DELIMITER $$
CREATE PROCEDURE `CreateAreas`(
_areas varchar(21844),
_comparisonGroup varchar(21844),
_parentArea varchar(21844),
_areaType varchar(21844)
)
BEGIN
-- create temporary table "areas"
-- fill with area ids
create temporary table areas (
id int not null,
code varchar(30),
name varchar(100),
shortName varchar(100),
levelid int not null,
sortOrder int not null,
key (id)
);
-- assumes that only one of the 3 options is valid, areas, comparison group, bounded comparison group
if (_areas is not null) then
set @sql = concat('insert into areas (id, code, name, shortName, levelid, sortOrder) select id, Code, Name, ShortName, LevelID, 0 from GeoArea where Code in (''', replace(_areas, ',', ''','''), ''')');
prepare stmt from @sql;
execute stmt;
deallocate prepare stmt;
elseif (_comparisonGroup is not null) then
-- might not be the most efficient way, but is consistent with the approach above, and we do not expect the list to be long
insert into areas (id, code, name, shortName, levelid, sortOrder)
select GeoAreaID, GeoArea.Code, GeoArea.Name, GeoArea.ShortName, GeoArea.LevelID, SortOrder
from ComparisonGroupGeoAreaLink
INNER JOIN
GeoArea
ON GeoArea.ID = GeoAreaID
where ComparisonGroupID = (select id from ComparisonGroup where Identifier = _comparisonGroup)
and IsMember = 1;
elseif (_parentArea is not null and _areaType is not null) then
-- might not be the most efficient way, but is consistent with the approach above, and we do not expect the list to be long
insert into areas (id, code, name, shortName, levelid, sortOrder)
select a.ID, a.Code, a.Name, a.ShortName, a.LevelID, 0
from (select id from GeoArea where Code = _parentArea) as t
INNER JOIN
GeoAreaLinkCache c
ON
c.ParentAreaID = t.id
inner join GeoArea a
on c.ChildAreaID = a.ID
INNER JOIN
(select id from GeoAreaLevel where Identifier = _areaType) as l
ON
a.LevelID = l.id;
elseif (_areaType is not null) then
-- might not be the most efficient way, but is consistent with the approach above, and we do not expect the list to be long
set @sql = concat('insert into areas (id, code, name, shortName, levelid, sortOrder)
select a.ID, a.Code, a.Name, a.ShortName, a.LevelID, 0
from
(select id from GeoAreaLevel where Identifier in (''', replace(_areaType, ',', ''','''), ''')) l
INNER JOIN
GeoArea a
ON
a.LevelID = l.id');
prepare stmt from @sql;
execute stmt;
deallocate prepare stmt;
end if;
END
答案 0 :(得分:0)
是的,这是可能的。我们没有测量这需要多长时间,但是可以预期临时表在创建它时会产生一些开销,将数据写入其中,查询它然后丢弃它。这种情况多久被召唤一次?
此外,通常已知MySQL的存储过程效率很低。它们不像Oracle和其他RDBMS品牌那样保留程序的编译形式。换句话说,每个会话都会重新编译它在第一次调用时使用的每个过程。
首先,我建议删除临时表。只需设计嵌套过程即可将正确的SQL查询构建为字符串,并返回该字符串。然后外部过程执行查询是其结果。您应该能够跳过临时表的创建/删除,以及插入临时表。
其次,如果我正在设计这个应用程序,我认为不需要任何存储过程。我建议编写代码在您的应用程序中构建正确的SQL查询,然后从应用程序执行该查询。
答案 1 :(得分:0)
似乎嵌套的SP不是主要的瓶颈。
我已经将临时表更改为MEMORY引擎,它确实做到了这一点并且让AMAZING产生了惊人的差异。
中提出了解决方案create temporary table areas (
id int not null,
code varchar(30),
name varchar(100),
shortName varchar(100),
levelid int not null,
sortOrder int not null,
key (id)
) ENGINE=MEMORY;