3

カーソルを使用してMysqlプロシージャを作成しましたが、実行速度が遅すぎます... 1秒あたり40〜60行になります。参照:

DELIMITER $$
CREATE PROCEDURE sp_create(IN v_idsorteio INT,OUT afetados INT)
  BEGIN
        DECLARE done INT default 0;
        DECLARE vc_idsocio INT;
        DECLARE z INT;
        DECLARE cur1 CURSOR FOR select IdSocio from socios where Sorteio=1  and Finalizado='S' and CodClientes IS NOT NULL;
        DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
        SET z=1;
        OPEN cur1;
        FETCH cur1 INTO vc_idsocio;
        WHILE done=0 DO
            -- SELECT register as t; 
            insert INTO socios_numeros_sorteio (IdSocio,IdSorteio,NumerodeSorteio) VALUES (vc_idsocio,v_idsorteio,z);
            FETCH cur1 INTO vc_idsocio;
            SET z = z+1;
        END WHILE;
        CLOSE cur1;
        Select z-1 as total INTO afetados;
  END$$
DELIMITER ;

どうすればそれを改善できますか?

4

2 に答える 2

11

結果セットを行ごとにループし、返された行ごとに個別の挿入ステートメントを実行しているため、これは低速です。だから遅くなるでしょう。

あなたがしていることを簡単に要約しましょう。まず、クエリを実行しています。

select IdSocio
  from socios
 where Sorteio=1
   and Finalizado='S'
   and CodClientes IS NOT NULL;

(明らかに、これらの行が返される順序は重要ではありません。)

次に、そのクエリから返された行ごとに、別のテーブルに行を挿入します。

insert INTO socios_numeros_sorteio
(IdSocio
,IdSorteio
,NumerodeSorteio
) VALUES
(vc_idsocio
,v_idsorteio
,z);

最初の列の値は、クエリによって返された値から取得されます。2番目の列の値には、プロシージャに引数として渡される値が割り当てられています。また、3番目の列の値は、1から始まり、行ごとに1ずつ増加するカウンターからのものです。

MySQLは、このような操作を実行するように最適化されています。ただし、カーソルを行ごとにループするストアドプロシージャを使用してこれを行うことは最適化されていません。

ある程度のパフォーマンスを得たい場合は、実行する個々のINSERTステートメントの数を大幅に減らし、代わりに、個々の行ではなく「セット」でデータを処理することを検討する必要があります。1つのアプローチは、行を「extended insert」ステートメントにバッチ処理することです。これにより、一度に複数の行を挿入できます。(1つのステートメントに挿入できる行数は、max_allowed_pa​​cketによって事実上制限されます。)

このアプローチはパフォーマンスを大幅に向上させますが、カーソルのオーバーヘッドを回避せず、各行をプロシージャ変数にフェッチします。

このようなもの(プロシージャの本体)は、selectから結果セットを取得し、更新に煩わされることなく、すべての行を1回の急降下で宛先テーブルに挿入するため、はるかに優れたパフォーマンスを発揮する可能性があります。プロシージャ内の変数の値。

BEGIN

SET @idsorteio = v_idsorteio;

INSERT INTO socios_numeros_sorteio
( IdSocio
, IdSorteio
, NumerodeSorteio
)
SELECT s.IdSocio   AS IdSocio
     , @idsorteio  AS IdSorteio
     , @z := @z+1  AS NumerodeSorteio
  FROM socios s
  JOIN (SELECT @z := 0) z
 WHERE s.Sorteio=1
   AND s.Finalizado='S'
   AND s.CodClientes IS NOT NULL;

SELECT ROW_NUMBER() INTO afetados;

END$$
于 2012-07-19T20:16:02.083 に答える
2

もう1つの簡単な解決策は、以下のクエリを実行して、テーブルのエンジンをMyISAMに変更することだけです。

ALTER TABLE `socios_numeros_sorteio`
ENGINE=MyISAM;

次に、手順をもう一度呼び出します。注:MyISAMを使用すると、挿入プロセスが非常に高速になります

于 2017-09-07T10:56:40.140 に答える