数据库
首页 > 数据库> > MySql嵌套SP可以成为瓶颈吗?

MySql嵌套SP可以成为瓶颈吗?

作者:互联网

我们有这个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

解决方法:

是的,有可能.我们没有测量这需要多长时间的度量,但是可以期望一个临时表在创建,写入数据,查询,然后删除它时会造成一些开销.多少次被称为?

同样,众所周知,MySQL的存储过程效率很低.它们不像Oracle和其他RDBMS品牌那样保留过程的编译形式.换句话说,每个会话都会在第一次调用它时重新编译它使用的每个过程.

首先,我建议删除临时表.只需设计嵌套过程即可将正确的SQL查询构建为字符串,然后返回该字符串.然后外部过程执行查询就是它的结果.您应该能够跳过临时表的创建/删除,以及将其插入到临时表中.

其次,如果我正在设计此应用程序,则看不到任何一个存储过程都不需要.我建议编写代码以在您的应用程序中构建正确的SQL查询,然后从应用程序中执行该查询.

标签:performance,mysql,stored-procedures,database-performance
来源: https://codeday.me/bug/20191011/1893591.html