en créant un index sur to_number(num_serie),la requête quitte de 20s 33 à 1min 16.elle devient plus lente!!Essayez avec un index non pas sur num_serie mais sur to_number(serie).
en créant un index sur to_number(num_serie),la requête quitte de 20s 33 à 1min 16.elle devient plus lente!!Essayez avec un index non pas sur num_serie mais sur to_number(serie).
ok je vais devoir détruire mes données avant de modifier mon schéma.... si vous stockez des nombres vous devez utiliser le format NUMBER et pas VARCHAR2.
ok j'ai pas le choix apparemment. à plus!je vais essayé ca.a plus
ex. 1a
ex. 1b:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 create table num_serie_montant ( montant number, num_serie varchar2 (9)); create index num_serie_montant_ii on num_serie_montant (num_serie); insert into num_serie_montant (montant, num_serie) select trunc (level / 1000), to_char (level) from dual connect by level <= 10000000; commit; set timing on declare xstart number := 450; xend number := 5000; xres number; begin SELECT count(DISTINCT montant) into xres FROM num_serie_montant WHERE to_number(num_serie) BETWEEN xstart AND xend; end; / 00:00:13.49 -- pas bon
ex. 2
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 create index x on num_serie_montant (to_number(num_serie)); declare xstart number := 450; xend number := 5000; xres number; begin SELECT count(DISTINCT montant) into xres FROM num_serie_montant WHERE to_number(num_serie) BETWEEN xstart AND xend; end; / -- avec index "to_number" - ok 00:00:00.43
ex. 3 (la meilleure solution)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 create table num_serie_montant ( montant number, num_serie varchar2 (9)); create index num_serie_montant_ii on num_serie_montant (num_serie); insert into num_serie_montant (montant, num_serie) select trunc (level / 1000), lpad (to_char (level), 9, '0') from dual connect by level <= 10000000; commit; declare xstart varchar2 (9) := '000000450'; xend varchar2 (9) := '000005000'; xres number; begin SELECT count(DISTINCT montant) into xres FROM num_serie_montant WHERE num_serie BETWEEN xstart AND xend; end; / -- ok 00:00:00.90
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 create table num_serie_montant ( montant number, num_serie number (9)); create index num_serie_montant_ii on num_serie_montant (num_serie); insert into num_serie_montant (montant, num_serie) select trunc (level / 1000), level from dual connect by level <= 10000000; commit; declare xstart number := 450; xend number := 5000; xres number; begin SELECT count(DISTINCT montant) into xres FROM num_serie_montant WHERE num_serie BETWEEN xstart AND xend; end; / -- ok 00:00:00.73
merci beaucoup à toi pour vos propositions de solutions .c'est vraiment cool!mais dites moi DAB.cz pour la meilleure solution,cette partie sert à quoi?moi je charge mes numéros de serie et montant via sql loader.insert into num_serie_montant (montant, num_serie)
select trunc (level / 1000), level from dual connect by level <= 10000000;
commit;
juste pour comprendre un peu plus ca.c'est vraiment très cool à toi.je vais les tester.select trunc (level / 1000), level from dual connect by level <= 10000000;
commit;
J'ai voulu insérer quelques lignes (1000000).
Explanation:
C'est la requête hiérarchique sur la table interne "dual"
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 SQL> select trunc (level / 10), level 2 from dual 3 connect by level <= 25; TRUNC(LEVEL/10) LEVEL --------------- --------- 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 1 10 1 11 1 12 1 13 1 14 1 15 1 16 1 17 1 18 1 19 2 20 2 21 2 22 2 23 2 24 2 25
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 SQL> select * from dual; D - X
Ne comptez plus les montants distincts. Affectez directement le libelle du montant à la zone libellé. Quand il aurait plusieurs montants correspondant à la plage il y aura une erreur dans le select d’affectation que vous pouvez intercepter et afficher un message explicite.
Bref, y compris avec votre algorithme ça doit bien se passer. Donc vous devez fournir un peu plus du code et des explications pour qu’on arrive à identifier ce qui ne va pas.
ah ok j'ai compris.moi je charge avec Sql loader.ca ne doit pas poser de problème donc.merciJ'ai voulu insérer quelques lignes (1000000).
J'ai un peu l'impression qu'on parle un peu dans le flou là puisqu'il manque des infos...
Sanouphil, tu nous a montré le curseur, mais qu'est-ce qui te dis que c'est ce curseur qui pose problème (bien que je soit d'accord avec les remarques précédentes)
Je suppose que ton curseur sert à piloter une boucle, qu'y-a-t-il comme traitement à chaque itération de la boucle ?
.Ne comptez plus les montants distincts. Affectez directement le libelle du montant à la zone libellé. Quand il aurait plusieurs montants correspondant à la plage il y aura une erreur dans le select d’affectation que vous pouvez intercepter et afficher un message explicite.
Bref, y compris avec votre algorithme ça doit bien se passer. Donc vous devez fournir un peu plus du code et des explications pour qu’on arrive à identifier ce qui ne va pas.
Mon premier curseur est comme ceci :
mon deuxième curseur :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 cursor cnt is select count(distinct montant) from activation.num_serie_montant where num_serie between :starting_id and :ending_id;
Ensuite j'ouvre mes curseurs comme ceci :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 cursor mnt is select distinct montant from activation.num_serie_montant where num_serie between :starting_id and :ending_id;
J'ouvre mon second curseur comme ceci :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 open cnt; fetch cnt into nbr; close cnt; if nbr > 1 then message alert elsif nbr=0 message alert else
Et j'affecte les valeurs récupérées aux différents champs.
Code : Sélectionner tout - Visualiser dans une fenêtre à part open mnt; fetch mnt into v_montant; close mnt;
il y a un autre curseur qui contient la jointure entre la table produit et la table num_serie_montant.
J'espère que c'est plus clair maintenant.
Merci.
Petite remarque, ton premier curseur est inutile étant donné que tu ne ramènes qu'une seule valeur, fait plutot:
ça revient au même mais c'est plus vite écrit!
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 SELECT count(DISTINCT montant) into nbr FROM activation.num_serie_montant WHERE num_serie BETWEEN starting_id AND ending_id;
Etant donné tu sors lorsqu'il y a plusieurs montants, ça veut dire que ton 2ieme curseur lui aussi ne renvoit qu'une valeur!
Tu peux donc faire
étant donné que tu fais 2 fois le meme parcours pour une fois vérifier, et une autre fois charger ta variable, tu peux mutualiser par exemple par
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 SELECT DISTINCT montant into v_montant FROM activation.num_serie_montant WHERE num_serie BETWEEN :starting_id AND :ending_id;
ça marchera exactement pareil et tu économiseras un parcours de table et là de 2 choses l'une:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 SELECT MAX(montant) , count (distinct v_montant) into v_montant, nbr FROM activation.num_serie_montant WHERE num_serie BETWEEN starting_id AND ending_id;
- soit tu a divisé tes temps par 2 (enfin un peu moins à cause du cache) et tu as un pb de très gros volume de données dans ta table
- soit ça n'a rien changé (ce que je crois) et ça veut dire que le pb vient de l'autre partie que tu n'as pas montré
Il faut aussi la syntaxe du dernier curseur, afin qu'on puisse tous les supprimer !
ainsi cela veut-il dire que je n'aurai plus besoin de mes curseurs?Petite remarque, ton premier curseur est inutile étant donné que tu ne ramènes qu'une seule valeur, fait plutot:
la syntaxe du dernier curseur est ceci:
ensuite j'ouvre mon curseur et j'affecte le libellé à la forms
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 CURSOR C IS SELECT libellé,prix_unitaire FROM produits WHERE code_produit=code_plage;
et c'est tout!
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 begin open c; fetch c into :libellé,:prix_unitaire;close c; :forms.libellé:=:libellé;
j'espère encore que c'est claire!
merci pour votre aide
Comment faites-vous le lien entre code_plage et le curseur précédent, est-ce le montant du deuxième curseur ?
là aussi si tu es sur que ton curseur ne te ramène qu'une ligne, tu peux faire un "select into"
A priori si c'est cette dernière requete qui est la cause, ça peut venir de 2 trucs:
- Est-ce que ta table produits est bien indexée sur "code_produit" ?
- Est-ce que la variable code_plage est du même type que "code_produit" car si jamais la variable est de type number et que la colonne est de type varchar2, il peut y avoir une réécriture implicite de la requête par
Et du coup ça ne passe plus par l'index de code_produit. Il faut donc soit faire un index sur le to_number là aussi, soit se débrouiller pour que les types soient les mêmes.
Code : Sélectionner tout - Visualiser dans une fenêtre à part to_number(code_produit) = code_plage
le lien entre les curseurs est que la table produits dispose déjà à l'avance des montants et des libellés que peut prendre une plage donnée.donc effectivement c'est le montant du deuxième curseur qui fait le lien
Code : Sélectionner tout - Visualiser dans une fenêtre à part Comment faites-vous le lien entre code_plage et le curseur précédent, est-ce le montant du deuxième curseur ?
j'ai pas d'index sur le code du produit enfin je n'en ai pas crée.faut-il que je le fasse?et puis la colonne code_produit est effectivement de type varchar2(7) et libellé de type VARCHAR2(30).je vais donc changer le type du code produit pour voir.Et du coup ça ne passe plus par l'index de code_produit. Il faut donc soit faire un index sur le to_number là aussi, soit se débrouiller pour que les types soient les mêmes.
Merci pour la remarque.
Si j'ai bien tout compris (et j'ai un sérieux doute car vous livrez les informations au compte-goute, c'est un peu pénible), vous pouvez tout synthétiser en une seule requête :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 SELECT case count(distinct prd.code_produit) when 1 then 'OK' else 'Plusieurs produits sur la plage saisie' end as statut, case count(distinct prd.code_produit) when 1 then min(prd.libellé) end as libellé, case count(distinct prd.code_produit) when 1 then min(prd.prix_unitaire) end as prix_unitaire INTO :statut, :libellé, :prix_unitaire FROM activation.num_serie_montant nsm inner join produits prd on prd.code_produit = nsm.montant WHERE to_number(nsm.num_serie) BETWEEN :starting_id AND :ending_id;
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager