2

ネストされた SP を呼び出すこの MySQL 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
4

2 に答える 2

0

はい、可能です。これにかかる時間の測定値はありませんが、一時テーブルを作成し、データを書き込み、クエリを実行してから削除すると、一時テーブルがオーバーヘッドを引き起こすことが予想されます。これはどのくらいの頻度で呼び出されますか?

また、MySQL のストアド プロシージャは一般にかなり非効率的であることが知られています。Oracle やその他の RDBMS ブランドのように、コンパイルされた形式のプロシージャは保持されません。つまり、すべてのセッションは、最初に呼び出されたときに使用する各プロシージャを再コンパイルします。

まず、一時テーブルを削除することをお勧めします。適切な SQL クエリを文字列として作成し、その文字列を返すようにネストされたプロシージャを設計するだけです。次に、外側のプロシージャがクエリを実行し、その結果になります。一時テーブルの作成/削除、および一時テーブルへの挿入をスキップできるはずです。

第 2 に、私がこのアプリを設計している場合、どちらのストアド プロシージャも必要ないと思います。アプリケーションで適切な SQL クエリを作成するコードを作成し、アプリケーションからそのクエリを実行することをお勧めします。

于 2013-11-05T16:32:05.330 に答える
0

ネストされた SP が主なボトルネックではなかったようです。

一時テーブルを MEMORY エンジンに変更したところ、本当に効果があり、驚くべき違いが生まれました。解決策が提案されました

https://dba.stackexchange.com/questions/52825/can-mysql-nested-sp-be-a-bottleneck/52863?noredirect=1#52863

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;
于 2013-11-06T15:48:10.127 に答える