Cette opération est lente car vous effectuez une boucle dans un ensemble de résultats, ligne par ligne, et exécutez des instructions d'insertion individuelles pour chaque ligne renvoyée. C'est pourquoi ça va être lent.
Résumons brièvement ce que vous faites. Tout d'abord, vous exécutez une requête:
select IdSocio
from socios
where Sorteio=1
and Finalizado='S'
and CodClientes IS NOT NULL;
(. Apparemment, l'ordre de ces lignes sont renvoyées dans n'a pas d'importance)
Ensuite, pour chaque ligne renvoyée de cette requête, vous voulez insérer une ligne dans un autre table.
insert INTO socios_numeros_sorteio
(IdSocio
,IdSorteio
,NumerodeSorteio
) VALUES
(vc_idsocio
,v_idsorteio
,z);
La valeur de la première colonne provient d'une valeur renvoyée par la requête. La valeur de la deuxième colonne est affectée d'une valeur passée en tant qu'argument à la procédure. Et la valeur de la troisième colonne provient d'un compteur qui commence à 1 et est incrémenté de 1 pour chaque ligne. MySQL est optimisé pour effectuer une opération comme celle-ci. Mais ce n'est PAS optimisé pour le faire en utilisant une procédure stockée qui parcourt un curseur ligne par ligne. Si vous souhaitez obtenir des performances raisonnables, vous DEVEZ REDUIRE DE MANIÈRE SIGNIFICATIVE le nombre d'instructions INSERT individuelles que vous exécutez, et penser plutôt au traitement des données dans des "ensembles" plutôt qu'à des lignes individuelles. Une approche consiste à grouper les lignes dans des instructions "insert étendu", qui peuvent insérer plusieurs lignes à la fois. (Le nombre de lignes que vous pouvez insérer dans une instruction est effectivement limité par max_allowed_packet.)
Cette approche améliorera de manière significative les performances, mais elle n'évite pas le surdébit du curseur, en récupérant chaque ligne dans les variables de procédure. Quelque chose comme cela (dans le corps de votre procédure) est susceptible de fonctionner beaucoup, beaucoup mieux, car il prend le jeu de résultats de votre sélection et insère toutes les lignes dans la table de destination d'un seul coup, sans déranger de jouer avec la mise à jour des valeurs des variables dans la procédure.
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$$
I seconde, 'INSERT .. select' est un excellent outil pour apprendre – spacediver
Excellente réponse :) –
Un avertissement est nécessaire en ce qui concerne cet exemple. Les tables impliquées dans de telles instructions d'insertion resteront verrouillées pendant la durée de l'insertion, empêchant ainsi d'autres actions (par exemple, sélectionner, insérer, mettre à jour, supprimer) sur les tables tant que le verrou est en place. –