我们有这个MySQL SP,它使用动态SQL。 它似乎在负载下表现不佳。
这个SP在加载时可能变慢,因为它使用动态SQL? 动态SQL是否会导致MySql中的性能问题(例如,因为它没有被引擎缓存)?
请注意,此SP是从其他几个SP调用的。它使用临时表将结果传递给父SP。
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 :(得分:1)
是。存储过程的一个优点是可以解析它们,可以缓存查询计划等等。
动态SQL(或即席查询)没有这样的优势。
也就是说,您的性能瓶颈不太可能来自动态SQL,更可能是因为缺少索引,插入/删除过多等等。
答案 1 :(得分:0)
播放从插入中删除子查询(未测试)。可能值得尝试对这些查询进行解析(以及SELECT部分),并将它们与原始SP中的EXPLAINS进行比较。
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
INNER JOIN ComparisonGroup
ON ComparisonGroupID = ComparisonGroup.id
WHERE ComparisonGroup.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 GeoArea t
INNER JOIN GeoAreaLinkCache c
ON c.ParentAreaID = t.id
inner join GeoArea a
on c.ChildAreaID = a.ID
INNER JOIN GeoAreaLevel l
ON a.LevelID = l.id
where l.Identifier = _areaType
AND Code = _parentArea;
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 GeoAreaLevel l
INNER JOIN GeoArea a
ON a.LevelID = l.id
where l.Identifier in (''', replace(_areaType, ',', ''','''), ''')');
prepare stmt from @sql;
execute stmt;
deallocate prepare stmt;
end if;
END
答案 2 :(得分:0)
似乎动态SQL不是瓶颈。
我已经将临时表更改为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;