[Oracle/PL-SQL] Passer un tableau en paramètre d'une procedure stockée

Passer un tableau en paramètre d'une procedure stockée [Oracle/PL-SQL] - SQL/NoSQL - Programmation

Marsh Posté le 02-07-2004 à 15:43:23    


Je dois insérer un grand nombre d'enregistrement (plusieurs dizaines de milliers) dans une table à la suite. Pour optimiser cette opération, j'ai pensé à utiliser une procedure stockée qui prendrait un tableau (ou une collection ou n'importe quoi d'approchant) en paramètres plutot que d'appeller 20000 fois la même procedure.
1)Est-ce possible ?
2)Si oui, Comment dois-je m'y prendre ?
3)1+2 via les composants ADO ?
 
D'avance merci
 
 :hello:


---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 02-07-2004 à 15:43:23   

Reply

Marsh Posté le 02-07-2004 à 16:13:01    

Ils viennent d'où tes enregistrements?


---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 02-07-2004 à 16:20:57    

skeye a écrit :

Ils viennent d'où tes enregistrements?


de ton cul évidemment [:petrus75]
Ils viennent de données entrées par l'utilisateur (enfin, pas saisies à la main, mais c'est tout comme).


---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 02-07-2004 à 16:34:46    

1) oui.
2) je sais plus
3) les ADOs c'est des trucs de pédophiles


---------------
trainoo.com, c'est fini
Reply

Marsh Posté le 02-07-2004 à 16:36:37    

skeye a écrit :

Ils viennent de données entrées par l'utilisateur (enfin, pas saisies à la main, mais c'est tout comme).


Tu veux dire qu'un utilisateur est capable de saisir plus d'un millier d'enregistrements à la suite avec ses propres pieds :??: :ange:


Message édité par Ummon le 02-07-2004 à 16:37:02
Reply

Marsh Posté le 02-07-2004 à 16:38:35    

Ummon a écrit :

Tu veux dire qu'un utilisateur est capable de saisir plus d'un millier d'enregistrements à la suite avec ses propres pieds :??: :ange:


Je t'arrête tout de suite, j'ai jamais écrit ça!:o


---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 02-07-2004 à 16:39:18    

Ummon a écrit :

Tu veux dire qu'un utilisateur est capable de saisir plus d'un millier d'enregistrements à la suite avec ses propres pieds :??: :ange:


c'est peut-être des données entrées en 20 ans, qui sait ?


---------------
What if I were smiling and running into your arms? Would you see then what I see now?  
Reply

Marsh Posté le 02-07-2004 à 16:44:46    

Ummon a écrit :

Tu veux dire qu'un utilisateur est capable de saisir plus d'un millier d'enregistrements à la suite avec ses propres pieds :??: :ange:


JagStang a écrit :

c'est peut-être des données entrées en 20 ans, qui sait ?


L'origine des données n'est pas le problème :o


---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 02-07-2004 à 16:45:59    

nraynaud a écrit :

1) oui.
2) je sais plus
3) les ADOs c'est des trucs de pédophiles


1) cool [:icon10]
2) dommage :(
3) Je n'ai pas souvenir de ces faits monsieur le juge :ange:


---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 02-07-2004 à 23:02:13    

Je suppose que chaque entrée du tableau de ton programme VB contiendrait la donnée à insérer dans ta base, et que dans ta procédure stockée, tu prends chaque entrée de ce tableau, et tu l'INSERT dans ta base.
 
Le client Oracle de Microsoft ne permet pas de passer des tableaux en argument à des procédures stockées (ou alors j'ai jamais réussi à y arriver, mais dans ce cas je suis pas le seul)
 
La meilleure solution, est de mettre toutes les entrées de ton tableau dans une grande chaine de caractères, séparées par des virgules, puis de passer cette chaine en argument à une procédure stockée.
Puis, dans la procédure stockée, il faudra que tu parses cette chaine pour séparer les données, en utilisant la virgule comme séparateur. Puis réalise ton INSERT pour chaque donnée extraite.
 
Tu peux parser la chaine en utilisant les fonctions INSTR, SUBSTR, LTRIM et RTRIM de PL/SQL.
 
Bref, bon courage, c'est pas simple :/


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 02-07-2004 à 23:02:13   

Reply

Marsh Posté le 02-07-2004 à 23:19:34    

merci, je vais voir ce que je peux faire avec ça.


---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 02-07-2004 à 23:23:45    

dans mes rechrches sur google, je suis tombé sur cet article:
http://www.databasejournal.com/fea [...] hp/3318791
 
avec les méthodes qu'il donne, je pense avoir trouvé le moyens d'envoyer des tableaux de valeurs en paramètre d'une procedure stockée, je testerai ça lundi matin :)


---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 02-07-2004 à 23:26:31    

ça a l'air sympa [:figti]
si tu y arrives, poste le code de ta procédure, ça m'intéresse ;)


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 03-07-2004 à 01:02:56    

tu peux pas utiliser un type de données TABLE ?

Reply

Marsh Posté le 03-07-2004 à 01:16:12    

HappyHarry a écrit :

tu peux pas utiliser un type de données TABLE ?


Vu que je veux insérer des valeurs qui ne sont pas dans la base, je ne pense pas, mais si tu as une méthode pour faire ça, je suis à l'écoute.


---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 03-07-2004 à 13:26:15    

ben tu peux passer un argument de types "table d'entier" en parametre d'une proc, ce qui correspond a un tableau [:spamafote]

Reply

Marsh Posté le 03-07-2004 à 13:35:16    

Comment je fais ça avec les ADO ?


---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 03-07-2004 à 13:45:49    

ca c'est une autre histoire [:ddr555]
 
j'avais essayé en ASP un jour, j'avais pas réussi :/


Message édité par HappyHarry le 03-07-2004 à 13:45:59
Reply

Marsh Posté le 05-07-2004 à 17:09:49    

Bonne nouvelle: J'ai réussi \o/
Mauvaise nouvelle: C'est 4 à 5 fois plus lent en utilisant des tableaux /o\
 
Si ça vous intéresse, je poste le code qui permet tout ça.


---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 05-07-2004 à 17:44:05    

t'as fait comment finalement ?

Reply

Marsh Posté le 05-07-2004 à 17:51:14    

CREATE TABLE TABLETEST
(
  IDTABLETEST  NUMBER(6)                        NOT NULL,
  NOM          VARCHAR2(25)
);
 
CREATE TYPE TEST_TY AS OBJECT (V_ID NUMBER, NOM VARCHAR2(25));
CREATE TYPE TEST_ARRAY AS VARRAY(10000) OF TEST_TY;
 
 
CREATE OR REPLACE PROCEDURE TestInsertArray(ARRAY_INSERT IN TEST_ARRAY)
AS
BEGIN
  For i in 1..ARRAY_INSERT.COUNT Loop
    INSERT INTO TABLETEST(IDTABLETEST, NOM) VALUES(ARRAY_INSERT(i).V_ID, ARRAY_INSERT(i).NOM);
  End Loop;
END TestInsertArray;
/


Code VB:

Code :
  1. 'Cette fonction renvoit le temps (en secondes) que met oracle à insérer les elements
  2. 'ATTENTION, la taille des "programmes" est limitée dans Oracle (chez moi ça plante quand lNbRequetes est >2519)
  3. Public Function TestInsert(lNbRequetes As Long, ADOConnection as ADODB.Connection) As Single
  4.   Dim sngResult As Single
  5.   Dim sSqlRequest As String
  6.   Dim i As Long
  7.   sSqlRequest = "BEGIN" & vbCrLf & "TestInsertArray(TEST_ARRAY("
  8.   For i = 1 To lNbRequetes
  9.     sSqlRequest = sSqlRequest & "TEST_TY(" & CStr(i) & ",'DTC'),"
  10.   Next
  11.   sSqlRequest = Left(sSqlRequest, Len(sSqlRequest) - 1) & " ));" & vbCrLf & "END;"
  12.  
  13.   sngResult = Timer
  14.   ADOConnection.BeginTrans
  15.   ADOConnection.Execute sSqlRequest, , adExecuteNoRecords
  16.   ADOConnection.CommitTrans
  17.   TestInsert= Timer - sngResult
  18. End function


 
Requete envoyée à Oracle:
 

BEGIN
TestInsertArray(TEST_ARRAY(TEST_TY(1,'DTC'),TEST_TY(2,'DTC'),TEST_TY(3,'DTC'));
END;


Message édité par mareek le 05-07-2004 à 17:53:42

---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 06-07-2004 à 09:01:00    

ça intéresse qqn si je poste les différences de perfs selon la méthode utilisée ou bien je laisse mourir ce topic tranquillement ?


---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 06-07-2004 à 09:10:20    

non vas-y envoie


---------------
What if I were smiling and running into your arms? Would you see then what I see now?  
Reply

Marsh Posté le 06-07-2004 à 10:04:48    

Pour 100000 insertions:


Sans rien :                                      980,531 s.
Blocs :                                          273,453 s.
Transaction :                                    387,311 s.
Blocs + Transaction :                            270,156 s.
proc :                                          1881,984 s.
Blocs + proc :                                   138,030 s.
Transaction + proc :                            1004,984 s.
Blocs + Transaction + proc :                      40,640 s.
Blocs + proc + tableaux :                        265,077 s.
Blocs + Transaction + proc + tableaux :          238,124 s.


lexique:
-sans rien: execute les requêtes d'insertion une par une.
-Blocs: execute toutes les requêtes d'insertion en une seule fois dans un bloc BEGIN ... END;
-Transaction: exetute les requêtes dans une transaction.
-Proc: utilise une procedure stockee pour faire l'insert (un insert par procedure)
-proc + tableaux: utilise une procedure stockee qui prend un tableau en paramètre (tous les insert d'un seul coup).


Message édité par mareek le 06-07-2004 à 10:06:13

---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 06-07-2004 à 10:06:38    

résultats impressionnants... surtout en tre 1004 et 40 s...


---------------
What if I were smiling and running into your arms? Would you see then what I see now?  
Reply

Marsh Posté le 06-07-2004 à 10:07:09    

merci en tout cas :jap:


---------------
What if I were smiling and running into your arms? Would you see then what I see now?  
Reply

Marsh Posté le 06-07-2004 à 10:09:04    

JagStang a écrit :

résultats impressionnants... surtout en tre 1004 et 40 s...


t'en as sauté un ;)

proc :                                          1881,984 s.


---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 06-07-2004 à 10:10:24    

je compare pas le meilleur et le moins bon résultat. Mais des résultats qui me semblaient comparable,  
 
Transaction + proc :                            1004,984 s.
Blocs + Transaction + proc :                      40,640 s.


---------------
What if I were smiling and running into your arms? Would you see then what I see now?  
Reply

Marsh Posté le 06-07-2004 à 10:21:14    

OK.
 
Moralité, les tests cai bon, mangézen [:joce]


Message édité par mareek le 06-07-2004 à 10:21:33

---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 07-07-2004 à 10:21:13    

:jap: :jap:


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 10-07-2004 à 03:37:09    

Pense bête:
 

  • Penser à ajouter le beginTrans et comitTrans


  • Insertion/Maj des asso TypeH:

1-delete de tout les couples IDAFFPH/IDTYPEH à insérer/updater (une seule reqête, aucun risque d'erreur)
2-Passage de l'IDETAT à 3 sur toutes les asso contenant un IDAFFPH à insérer/updater (une seule reqête, aucun risque d'erreur)
3-Insérer les couples IDAFFPH/IDTYPEH à insérer/updater  


---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 17-11-2004 à 21:22:16    

Quelqu'un a déjà utilisé le FORALL ?  Notre DBA m'en a parlé aujourd'hui et ça a l'air d'être le moyen idéal de faire ce que je cherche à faire. :)
 
je testerai ça quand j'aurais le temps.
plus d'infos:
http://tahiti.oracle.com/pls/tahit [...] tion=48873


---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 17-11-2004 à 23:35:48    

ça a l'air cool, je connaissais pas du tout :jap:


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 18-11-2004 à 17:36:21    

mareek a écrit :

L'origine des données n'est pas le problème :o


Bah si c'est un problème.
 
Parceque si tu peux passer par une table ou un truc similaire, il suffit que ta requête accepte une "table" (ou "curseur" ) en paramètre, et tu lances :
 
select maFonction(select mesdonnes from matable)

Reply

Marsh Posté le 18-11-2004 à 17:38:55    

mareek a écrit :

Bonne nouvelle: J'ai réussi \o/
Mauvaise nouvelle: C'est 4 à 5 fois plus lent en utilisant des tableaux /o\
 
Si ça vous intéresse, je poste le code qui permet tout ça.


arf :D

Reply

Marsh Posté le 18-11-2004 à 17:42:27    

Relis le topic, ça t'évitera de débarquer 6 mois après avec une non solution :o


---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 19-11-2004 à 21:25:28    

J'ai fait des tests avec le FORALL, mais je trouve des résultats bizarre :heink:
 
J'en parle à mon DBA lundi et je vous tiens au courant


---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 22-11-2004 à 20:45:50    

Après avoir corrigé le bug monstrueux dans mon programme de test (:ange:), j'ai enfin des résultats cohérents (toujours pour 100000 insertions):


Blocs + Transaction + proc :                             50,859 s.
Blocs + Transaction + proc + tableaux(Obj) :             393,9838 s.
Blocs + Transaction + proc + tableaux(Simple) :          38,37413 s.
Blocs + Transaction + proc + tableaux(Simple) + Forall : 23,95225 s.


(j'ai changé de serveur de test depuis les tests précédents)
 
 
Le gain apporté par le FORALL est donc assez intéressant. Et il y a de fortes chances pour que les écrats soient encore plus important dans la pratique vu que ma table de test n'est pas indexée et que le FORALL est censé gagner un temps precieux sur l'indexation.
A noter egallement que l'utilisation des objets en PL/SQL fait chuter les perfs de manière vertigineuse.  
 
 
 
Procedures stockées utilisées pour l'insertion via tableaux(Simple):
 


TYPE ARRAY_INT IS VARRAY(10000) OF NUMBER
TYPE ARRAY_STR IS VARRAY(10000) OF VARCHAR2(50)
 
CREATE OR REPLACE PROCEDURE TestInsertArrayNOObj(ARRAY_ID IN ARRAY_INT,ARRAY_NOM IN ARRAY_STR)
AS
BEGIN
  For i in 1..ARRAY_ID.COUNT Loop
    INSERT INTO TABLETEST(IDTABLETEST, NOM) VALUES(ARRAY_ID(i), ARRAY_NOM(i));
  End Loop;
END TestInsertArrayNOObj;
/


 
Procedures stockées utilisées pour l'insertion via tableaux(Simple)+ ForAll:
 

CREATE OR REPLACE PROCEDURE TestInsertArrayFORALL(ARRAY_ID IN ARRAY_INT,ARRAY_NOM IN ARRAY_STR)
AS
BEGIN
  FORALL i IN ARRAY_ID.FIRST..ARRAY_ID.LAST
    INSERT INTO TABLETEST(IDTABLETEST, NOM) VALUES(ARRAY_ID(i), ARRAY_NOM(i));
END TestInsertArrayFORALL;
/


 
 
 
 
 
Prochaine étape: regarder comment utiliser un FORALL avec des séquences.


---------------
"I wonder if the internal negative pressure in self pumping toothpaste tubes is adjusted for different market altitudes." John Carmack
Reply

Marsh Posté le 23-11-2004 à 14:34:10    

Question bête : pourquoi tu utilises pas sqlloader ?

Reply

Marsh Posté le 23-11-2004 à 14:37:30    

tomlameche a écrit :

Question bête : pourquoi tu utilises pas sqlloader ?


sûrement à cause de ça:
http://forum.hardware.fr/hardwaref [...] tm#t785112


---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed