Complément performances SQL

BoTTom |    Changer de couleur
            PERFORMANCES  S Q L
           --------------------
 
 Normalisation de la base :
 
  - respectez les formes normales pour une base de production
 
  ..........................................................................
  : toute colonne d'une table dépend directement et uniquement de la clé ! :
  :........................................................................:
 
  - mettez en place l'intégrité référentielle (cela créé des indexs)
 
  - ajoutez des contraintes CHECK (l'optimiseur en tient compte)
 
  - évitez les clefs composites
 
     préférez les clefs purement informatiques, voir les champs IDENTITY
 
  - évitez les colonnes "nullables" en tant que clef, réservez cette
     notion aux données ou c'est important (date de départ, prix, ...)
 


|    Changer de couleur
 
  - limitez les zones à taille variable (CHAR / VARCHAR)
 
    accèdez à une zone VARCHAR sous DB2/400, c'est deux I/O disque !
 
  - Ayez un dictionnaire de données afin qu'une information soit toujours
     codée de manière identique
 
    A EVITER ABSOLUMENT :
 
       - le n° de client packé dans un fichier, étendu dans l'autre
 
       - date dans un fichier et jour/mois/année dans l'autre
 
       - ...
 
     "mapper" une donnée (convertir) c'est toujours ne pouvoir utiliser
       aucun des index existant.
 
  - n'indexez que l'essentiel, un index c'est aussi des cycles CPU
     consommées lors des écritures et des mises à jour.
 


|    Changer de couleur
 
 Réutilisation des ODP (résultat d'un OPEN) et des index. 
 
    SQL laisse ouvert les ODP qu'il a créé afin de les réutiliser.
 
        DANS un PGM l'ODP ne sera ré-utilisé qu'avec le même n°
         d'instruction (==> Appel de pgm ou sous-pgm)
 
      La commande système RCLRSC ferme les ODP crées par SQL.
 
    SQL utilise des index d'accès pour les clauses WHERE
                                                   GROUP BY / ORDER BY
 
    S'ils existent, SQL les utilise, sinon il peut être ammené à les créer.
      (d'où l'interêt de créer des index définitifs. CREATE INDEX ou LF)
 
    Un index ne peut jamais être explicitement utilisé, c'est l'optimiseur
     (le moteur) qui décide en fonction, aussi, du contexte.
 
    dans certains cas un balayage complet du fichier sera moins pénalisant
    (en fonction du nombre de lignes et de la taille mémoire de votre AS)
 


|    Changer de couleur
SELECTION
 
 il faut bien voir que le but est de gagner du temps. Or ce qui prend le
  de temps, ce sont le E/S (I/O) disque.
 
 SQL va donc, TOUJOURS, chercher à optimiser la sélection.
 
  ce qui semble le plus évident, c'est l'utilisation d'index.
 
 Mais, l'utilisation d'un index pour sélectionner les enregistrements, va
  ensuite pénaliser les E/S pour remonter les lignes en mémoire.
 
 En effet, si les postes d'index sont contigus, les enregistrements ne le
  sont pas dans le fichier, du moins, pas dans l'ordre de l'index.
     ............          .......................................
     : A  : 003 :        1 : Vis en bois   :  45  : 12,34  :  C  :
     : B  : 006 :        2 : clou en papier: 122  : 33,44  :  F  :
     : C  : 001 :        3 : trombonne     :   2  : 55,34  :  A  :
     : D  : 005 :        4 : règle en fer  :  15  : 12,45  :  E  :
     : E  : 004 :        5 : tournevisse   :  55  : 22,22  :  D  :
     : F  : 002 :        6 : clé à pipe    :  92  : 99,00  :  B  :
     :..........:          :.....................................:


|    Changer de couleur
 
 Sur l'exemple qui précède, si'il faut prendre les enregistrements ayant
  la famille comprise entre C et D. il faudra aller chercher la ligne 1
  puis la ligne 5. Donc 2 I/O (peut-être trop éloignées pour une seule).
 
 S'il faut prendre tout ce qui est entre A et E, mieux vaudrait charger tout
  le fichier en mémoire et trier "manuellement".
 
 SQL va donc estimer le nombre de lignes correspondant à votre sélection.
 
 1/ en allant voir les infos tenues à jour par DB2/400 (V5R10)
 
    résultat de DSPFD sur un index classant les vins (25.221) par cépage.
  ..........................................................................
  :  Taille de l'index . . . . . . . . . . . :                     598016  :
  :  Validité du chemin d'accès  . . . . . . :            Oui              :
  :  Partage de chemin d'accès implicite . . :            Non              :
  :  Chemin d'accès journalisé . . . . . . . :            Non              :
  :  Nombre val clés partielles uniques  . . :                             :
  :    Zone clé 1  . . . . . . . . . . . . . :                        232  :
  :........................................................................:
ce qu'affiche aussi : select count(distinct vin_cepage1) from vins 


|    Changer de couleur
 
 2/ En réalisant des sondages dans les index, sur la première clé pour
     connaitre le nombre de valeurs par clé et en estimant le nombre
     de lignes correspondant à vos critères (voir les statistiques en V5.2)
 
 Il est possible que DB2 utilise l'index pour réaliser ces sondages et
  ne l'utilise pas pendant sa requête. Il aura quand même été utile !
 
 l'option de QAQQINI:OPTIMIZE_STATISTIC_LIMITATION peut limiter ces sondages
 ---------------------------------------------------------------------------
 L'intéret de ne pas utiliser d'index est dépendant de votre sous-système
  disque et votre mémoire principale.
 
JOINTURE
 
 Pour réaliser la jointure, DB2/400 utilise la plupart du temps
  une technique nommée "nested loop join" ou boucle imbriquée.
 
  il s'agit pour un n° de client, d'utiliser l'index classant les commandes
  par client, et ce pour chaque client (positionnement, lecture tant que...)
 
   ces index existent TOUJOURS avec l'intégrité référentielle !


|    Changer de couleur
 
 l'idéal étant de trouver un index portant sur la sélection ET le critère
  de jointure. par exemple :
 
   SELECT * FROM CLIENTS JOIN CDES on CLIENTS.NOCLI = CDES.NOCLI
            WHERE DEPCLI = 44
 
   si DB2 trouve un index sur NOCLI ET DEPCLI, il sera forcement utilisé.
   (jointure cdes vers clients, sauf LEFT JOIN ...)
 
 l'OPTION "FORCE_JOIN_ORDER" dans QAQQINI permet d'interdir à DB2/400
  de ré-agencer l'ordre des fichiers dans la clause FROM.
 
GROUPAGE
 
  s'il y a un petit nombre de lignes par GROUPE, DB2 va privilégier un index
   sinon, il va privilégier le Haschage. (voir plus loin)
 
TRI
 
  pour le tri, un index ou une routine de tri (SORT) va être utilisée.
 


|    Changer de couleur
    SQL n'utilise pas d'index dans les cas suivants:
 
    -   Plus de 20% des lignes correspondent à la sélection (clause WHERE)
 
    -   Comparaison entre deux arguments de type différent(CAST par exemple)
       ....................................................................
       :la requête suivante empèche l'utilisation d'un index sur fichier2 :
       : pour la jointure(il ne peut exister d'index année,mois,jour)     :
       :                                                                  :
       : fichier1 JOIN fichier2 on   AA = SUBSTR(DATE, 5 , 4)             :
       :                        and  MM = SUBSTR(DATE, 3 , 2)             :
       :                        and  JJ = SUBSTR(DATE, 1 , 2)             :
       :                                                                  :
       :la requête ci-dessous utilise un index sur "DATE"                 :
       :                                                                  :
       : fichier1 JOIN fichier2 on  (AA CONCAT MM CONCAT JJ) = DATE       :
       :..................................................................:
 
    -   Comparaison entre une variable alpha et un argument plus grand
          que la variable.
 
    -   Clause LIKE commencant par '%'


|    Changer de couleur
 
    -   Clause LIKE avec une variable HOST dans un pgm RPG ou COBOL.
                (dans ce cas il est plus intéressant d'utiliser SQL
                   dynamique avec PREPARE et EXECUTE)
 
    -   Comparaison de deux colonnes de la même ligne.
 
    -   éviter les index sur un champs VARCHAR(), ils sont mal gérés par DB2
        (particulièrement, les statistiques vues sur DSPFD)
 
    -   éviter la valeur nulle admise, sur les clés importantes.
          (c'est impossible avec les PRIMARY KEY de toutes facons)
 
 
 Privilégiez la jointure avec JOIN (plus souple, plus lisible)
 
 
 Préférez EXISTS (traité en V5R10 comme une jointure) quand c'est possible :
 
  remplacez where (select count(*) from fichier where ....) = 0 
 
   par where NOT EXISTS (select * from fichier T02 where T02.clé=T01.clé) 


|    Changer de couleur
 Si vous souhaitez ignorer la casse (différence minuscules/majuscules)
  lors de vos recherches :
 
1/ utiliser UCASE, par exemple :
 
          Select * from VINS where ucase(cepage) like 'CABERNET%'
 
->le problème c'est que SQL ne peut réutiliser alors, aucun index existant
   avant la version 6.
 
2/ Utiliser un critère de tri particulier (paramètre SRTSEQ) : *LANGIDSHR
 
->si vous avez créé un index avec les mêmes attributs, il est utilisé !
 
  avec SDD, vous utilisez SRTSEQ( ) et LANGID( ) sur la commande CRTLF
 
  avec SQL, indiquez cette propriété pour la session SQL :
 
                     STRSQL SRTSEQ(*LANGIDSHR) LANGID(FRA)
 
                     sous ODBC/JDBC, onglet "Langue"  - Tri par ID Langue
                                                      - Poids partagé


|    Changer de couleur
 Version 6 
 
 A/ On admet les expressions en tant que clé
 
    CREATE INDEX i1 on table T1 ( UPPER(NOM) as NOMMAJ )
 
 la zone NOMMAJ est la clé de cet index.
 
 
 toute requête utilisant WHERE UPPER(NOM) like '...%', utilisera
  implicitement l'index en question à partir de la version7.
 
 
 l'expression ne peut pas contenir :
 
 
   - des sous requêtes
   - des fonctions agrégées (COUNT, AVG, SUM, etc ...)
   - des fonctions NOT DETERMINISTIC (dont le résultat varie), comme NOW()
   - des UDF sauf celles liées à un nouveau type de données (UDT)
   - la manipulation de SEQUENCE
   - des variables , des marqueurs ("?")


|    Changer de couleur
 
B/ On admet la clause WHERE sur les index :
 
    CREATE INDEX i1 on table T1 (NOM) WHERE NOM NOT LIKE 'VOL%'
 
    la clause WHERE subit les mêmes règles que les expressions
 
 C/ Vous pouvez préciser un format par la clause RCDFMT
 
    suivi de la phrase suivante :
 
     ADD ALL COLUMNS : toutes les colonnes du PF appartiennent au format
     ADD KEYS ONLY   : seules les zones clés appartiennent au format
     ADD col1, col2  : ces zones font suite aux zones clés dans le format
 
Exemple récapitulatif :
 
  CREATE INDEX logi1 on HTTPLOG
        ( SUBSTR(virtualhost, 1 , 10) VHOST2 )
       Where virtualhost IS NOT NULL
       RCDFMT httpfmt2 ADD host, logtime  -- en plus de VHOST2
 


|    Changer de couleur
 
 Certains SGBD utilisent la technique des index bitmap 
 
  soit la table suivante :
                                 l'index bitmap associé sera
     ##################### 
rang #  client   ville   #           valeur    bitmap
     #####################         ......................
 1   #  1        NANTES  #         : NANTES : 10000100  :
 2   #  6        ANGERS  #         : ANGERS : 01000000  :
 3   #  3        RENNES  #         : RENNES : 00100010  :
 4   #  7        CHOLET  #         : CHOLET : 00010000  :
 5   #  8        BREST   #         : BREST  : 00001000  :
 6   #  5        NANTES  #         : VANNES : 00000001  :
 7   #  4        RENNES  #         :........:...........:
 8   #  2        VANNES  #                    12345678
     #                   # 
     #####################      On place un "1" pour chaque enregistrement
                                 ayant cette clé à la position du n° de rang
 
                                pour "NANTES", les enregistrements 1 et 6.
 


|    Changer de couleur
 
  DB2/400 n'utilise pas les index bitmap, par contre la technologie bitmap
     est utilisée pour gérer vos requêtes avec des tests. (depuis la V4R20)
 
  Il utilise un index pour chaque critère, construit un nuage de points
    (bitmap) sur chaque résultat, et applique une fonction boolèenne AND/OR.
 
  le résultat indique par un "1" la liste des enregistrements ayant un
      critère (OR) ou vos critères (AND) vrai(s).
 
  NANTES ou ANGERS fournit 10000100
                   puis    01000000 
                           11000100 ==> les lignes 1,2 et 6.
 
  l'AS/400 est capable d'utiliser une technique de haschage pour les
    jointure. Cela consiste à fabriquer une table temporaire ou la position
    de l'enregistrement est dépendante de sa valeur de clé (hash-coding)
 
  Pour ces deux raisons, il est conseillé d'indiquer ALWCPYDTA(*OPTIMIZE) 
   qui autorise la copie des données, dans des fichiers temporaires.
 
      (ATTENTION, sous STRSQL ajoutez réaffichage *FORWARD )


|    Changer de couleur
 
 EVI enfin, qui est un concept Rochester (il y a un brevet), l'AS/400
  étant le premier à l'utiliser.
 
 EVI est une utilisation avancèe des index Bitmap
 
                                                               Vecteur
--------------------------                                    +------+
!rang   client   ville   !  ...........................       | code |
!------------------------!  : Table des symboles      :       +------+
!1  !   1     !  NANTES  !  :.........................:       |   1  | 1
!2  !   6     !  ANGERS  !  :Valeur:code:Deb:Fin: nbre:       |   2  | 2
!3  !   3     !  RENNES  !  :      :    :   :   :     :       |   3  | 3
!4  !   7     !  CHOLET  !  :NANTES: 1  : 1 : 6 :  2  :       |   4  | 4
!5  !   8     !  BREST   !  :ANGERS: 2  : 2 : 2 :  1  :       |   5  | 5
!6  !   5     !  NANTES  !  :RENNES: 3  : 3 : 7 :  2  :       |   1  | 6
!7  !   4     !  RENNES  !  :CHOLET: 4  : 4 : 4 :  1  :       |   3  | 7
!8  !   2     !  VANNES  !  :BREST : 5  : 5 : 5 :  1  :       |   6  | 8
!   !         !          !  :VANNES: 6  : 8 : 8 :  1  :       +------+
!------------------------!  :......:....:...:...:.....:
 
 On voit que les lignes 1 et 6 sont de code "1" c'est à dire NANTES.


|    Changer de couleur
 
  Le vecteur contient un poste par enregistrement, la position donnant le
    n° de rang, MAIS on indique un code et non une valeur de clé.
 
 
   On indique en plus une table des symboles qui contient
 
       - la correspondance entre chaque valeur de clé et son code associé
 
       - des statistiques destinées au "Query Governor", l'optimiseur de
                                                                    requêtes
 
   Il faut simplement indiquer le nombre de valeurs différentes lors de la
     création afin de savoir s'il faut créér un vecteur sur 1,2 ou 4 octets
 
   si vous ne connaissez pas ce nombre de valeurs différentes DB2 va les
     rechercher pour vous AU MOMENT DE LA CREATION (non réactualisé) .
 
       CREATE ENCODED VECTOR INDEX on fichier(clé1, clé2, ...)
 
                      FOR x DICTINCT VALUES 
 


|    Changer de couleur
 
 > les index EVI ne sont pas utilisables pour :
 
  - les jointures
 
  - le groupage d'enregistrements
 
  - le tri
 
 
 > les index EVI sont à conseiller pour :
 
  - un petit nombre de valeurs différentes avec beaucoup de lignes
    (famille de produit, département, année/semaine , etc...)
 
  - des données peu mouvantes (un produit change peu de famille)
 
  - des données en fort volume (gros fichiers)
 
 
 > DB2/400 va bien utiliser la technique bitmap sur DEUX index EVI (ou plus)
    portant chacun sur une SEULE colonne.


|    Changer de couleur
 Version 7 
 
 
 - Les index avec sélection d'enregistrement(avec une clause WHERE)
    sont maintenant pleinement utilisés par SQE
 
 
 
 - Nouvelle possibilité d'inclure des fonctions agrégées
    (SUM,AVG,COUNT,VAR,STDDEV) dans un index EVI.
 
 
     CREATE ENCODED VECTOR INDEX EVI01 ON COMMANDES
       (DATCMD, FAM)
 
       INCLUDE (SUM(QTE) , COUNT(*) )
 
 
 
     Avec le groupe PTF SF99701 level 18, les requêtes utilisant
       GROUPING SET, ROLLUP ou CUBE, bénéficient aussi de ce type d'index.
 


|    Changer de couleur
 
 quelques exemples :
 
 SELECT * FROM PRODUITS where COULEUR in ('BLEU', 'VERT' ,'ROUGE')
 
 ==> CREATE INDEX PROD_IB01 ON PRODUITS (COULEUR)
 
      ou
 
     CREATE ENCODED VECTOR INDEX PROD_IE01 ON PRODUITS (COULEUR)
 
 
 SELECT * FROM PRODUITS where COULEUR in ('BLEU', 'VERT' ,'ROUGE')
                          and TAILLE in ('L' , 'XL')
 
 ==> CREATE INDEX PROD_IB02 ON PRODUITS (COULEUR, TAILLE)
     [si possible, la clé la plus sélective en 1er]
 
      ou
 
     CREATE ENCODED VECTOR INDEX PROD_IE01 ON PRODUITS (COULEUR)
     CREATE ENCODED VECTOR INDEX PROD_IE02 ON PRODUITS (TAILLE)


|    Changer de couleur
 
 SELECT * FROM PRODUITS where COULEUR in ('BLEU', 'VERT' ,'ROUGE')
                          and TAILLE in ('L' , 'XL')
                          and FIBRE  = 'COTON'
 
 ==> CREATE INDEX PROD_IB03 ON PRODUITS (COULEUR, TAILLE, FIBRE)
 
      ou
 
     CREATE ENCODED VECTOR INDEX PROD_IE01 ON PRODUITS (COULEUR)
     CREATE ENCODED VECTOR INDEX PROD_IE02 ON PRODUITS (TAILLE)
     CREATE ENCODED VECTOR INDEX PROD_IE03 ON PRODUITS (FIBRE)
 
 SELECT * FROM PRODUITS where COULEUR in ('BLEU', 'VERT' ,'ROUGE')
                            and TAILLE in ('L' , 'XL')
                            and FIBRE  = 'COTON' AND DISPO > 500
 
 ==> CREATE INDEX PROD_IB04 ON PRODUITS (COULEUR, TAILLE, FIBRE,DISPO)
 
        [la colonne testée par ">", doit être la dernière ! ]
 
      ou idem pour les index EVI [plus un pour "DISPO"]


|    Changer de couleur
 
 SELECT * FROM PRODUITS p JOIN CDES e on p.CODPRO=e.CODPRO
                          JOIN FAMILLES f on p.CODFAM=f.CODFAM
               where  COULEUR in ('BLEU', 'VERT' ,'ROUGE')
 
 ==> CREATE INDEX PROD_IB05 ON PRODUITS (COULEUR, CODPRO)
     CREATE INDEX PROD_IB06 ON PRODUITS (COULEUR, CODFAM)
 
   puis (s'ils n'existent pas déja du fait de l'intégrité ref.)
 
     CREATE INDEX CDES_IB01 ON CDES (CODPRO)
     CREATE INDEX FAM_IB01 ON FAMILLES (CODFAM)
 
 
 SELECT COULEUR, SUM(VALEUR), SUM(QTE)
    FROM PRODUITS where COULEUR in ('BLEU', 'VERT' ,'ROUGE')
                  group by COULEUR, TAILLE
 
 ==> CREATE INDEX PROD_IB02 ON PRODUITS (COULEUR, TAILLE)
 
        (pas d'evi)
 


|    Changer de couleur
 SELECT COULEUR, TAILLE, MIN(QTE)
    FROM PRODUITS where COULEUR in ('BLEU', 'VERT' ,'ROUGE')
                 group by COULEUR, TAILLE
 
 ==> CREATE INDEX PROD_IB07 ON PRODUITS (COULEUR, TAILLE, QTE)
 
 SELECT COULEUR, TAILLE, MAX(QTE)
    FROM PRODUITS where COULEUR in ('BLEU', 'VERT' ,'ROUGE')
                 group by COULEUR, TAILLE
 
 ==> CREATE INDEX PROD_IB08 ON PRODUITS (COULEUR, TAILLE, QTE desc)
                [desc est inutile avec le nouveau moteur SQE livré en V5R20]
 
 SELECT COULEUR, TAILLE, VENTES
    FROM PRODUITS where VENTES < (Select avg(ventes) From produits
                                    Where taille in ('L' , 'XL')   )
        and COULEUR in ('BLEU', 'VERT' ,'ROUGE')
        and TAILLE in ('L' , 'XL')
 
 ==> CREATE INDEX PROD_IB09 ON PRODUITS (TAILLE, COULEUR)
 
             [ici, TAILLE est privilégiée, car étant commune aux 2 requêtes]


|    Changer de couleur
 
 Bien sur, les index sont aussi utilisés sur les ordres UPDATE, DELETE :
 
 
 UPDATE PRODUIT SET PRIX = (Select MAX(PRIX) From CDES C
                                             Where C.CODFAM=p.CODFAM )
   WHERE COULEUR in ('BLEU', 'VERT' ,'ROUGE')
 
 ==> CREATE INDEX PROD_IB01 ON PRODUITS (COULEUR)
 
   et
 
     CREATE INDEX CDES_IB02 ON CDES (CODFAM , PRIX desc)
 
 
 
 DELETE FROM PRODUIT
        WHERE CODFAM in (12, 27, 456, 998)
         AND QTE = 0
 
 ==> CREATE INDEX PROD_IB10 ON PRODUITS (CODFAM, QTE)
 


|    Changer de couleur
 
 Vous pouvez aussi, optimiser SQL en utilisant le groupage d'enregistrements
 
   Clause OPTIMIZE FOR sur le SELECT [complétée par OVRDBF SEQONLY( ).] ,
 
   et choix d'un nombre de lignes sur les ordres FETCH et INSERT.
 
 
 Quelques comparatifs réalisés sur un Iseries POWER-PC (regardez les écarts)
 
 
 Ajouts d'enregistrements :
 
  Méthode       clause ROW      SEQONLY(*YES)    Enregistrements par minute
 ------------   ------------    -------------    --------------------------
 SQL (INSERT)     sans            sans                    2 300
 SQL              sans            avec                    6 300
 SQL             oui (100)        avec                   19 950
 
 RPG (Write)       -              sans                    3 800
 RPG               -              avec                   17 750
 


|    Changer de couleur
 
 Lecture séquentielle sur la clé :
 
                                               Nombre de    Enregistrements
  Méthode       clause ROW    SEQONLY(*YES)      zones         par minute
 ------------   ------------  -------------    ----------    --------------
 SQL (FETCH)      sans            sans            20            20 700
 SQL              sans            avec            20            22 200
 SQL             oui (100)        avec            20            39 450
 SQL             oui (100)        avec             3            44 100
 
 RPG (Read)        -              sans                          39 200
 RPG               -              avec                          42 850
 
 
 
 Contrairement à la mauvaise réputation de SQL, il est plus performant
  que les entrées/sorties natives à condition de limiter le nombre
  de colonnes extraites.
 
     (ces tests ont été faits en V3R60 avec RPG-IV)
 


|    Changer de couleur
 
 
 Lecture d'un groupe d'enregistrements avec clé :
                                               Nombre de    Enregistrements
  Méthode       clause ROW    SEQONLY(*YES)      zones         par minute
 ------------   ------------  -------------    ----------    --------------
 SQL (FETCH)      sans            sans            20            10 100
 SQL              sans            avec            20             9 750
 SQL             oui (10)         sans            20            11 900
 SQL             oui (10)         avec            20            11 900
 SQL             oui (10)         sans             3            12 750
 SQL             oui (10)         avec             3            12 100
 
 RPG (ReadE)       -              sans                          13 800
 RPG               -              avec                          13 650
 
 Ici, c'est RPG le "gagnant", ainsi que sur les ordres de mise à jour :
 
      Nombre maxi d'enregistrements mis à jour (par minute)
                  avec UPDATE SQL : 11 100
                  avec RPG        : 14 600
 


|    Changer de couleur
 
 Dernier point, SQL en tant que langage de conception de bases (DDL) :
 
 1/ CREATE TABLE
 
  un fichier physique créé par SDD contrôle mal les données insérées, il y
   a donc un contrôle supplémentaire réalisé lors de la lecture.
 
  Ce contrôle des données insérées étant mieux fait par SQL, les contrôles
   lors de la lecture n'ont pas lieu, elles sont donc plus rapides.
 
          Certains spécialistes chez IBM, parlent de 40% de gain !
 
 1/ CREATE INDEX
 
   les index créés par SQL contiennent un chemin d'accès basé sur des pages
     de 64 K,ceux créés par SDD sont au maximum à 32K (Op.nav le montre).
 
   ceci est dû à l'utilisation intensive faite pas SQL des indexs sur les
    grosses tables (décisionnelles particulièrement).
   Si vous avez de la mémoire disponible (il en faut aujourd'hui pour SQL)
    cela peut faire une véritable différence.


|    Changer de couleur
 
     Il est toujours possible de connaître les décisions de l'optimiseur
      de requêtes (méthode choisie, index utilisées, avertissements, ...)
 
     En 5250, il suffit d'être en mode DEBUG  (STRDBG sans paramètres)
 
     SQL va alors "loger" dans l'historique des informations sous forme
      de messages de type *INFO.
 
     Les C.A (index) explorés et les raisons pour lesquelles ils ont été
      soit retenus, soit écartés, sont indiquées dans le texte de
      second niveau,  et plus encore ...
 
     Exemple :
                                  ......................................
       STRDBG                     : Nous pouvons demander la même      :
                                  :  chose au gestionnaire de scripts  :
       CALL xxxx ou STRSQL.       :  SQL sous Iseries Navigator avec   :
                                  :  "Option/inclusion messages de     :
       DSPJOBLOG                  :     debogage dans l'historique"    :
                                  :....................................:
 


|    Changer de couleur
                             Historique du travail     
                                                             Système : -------- 
 Travail :   NANTEV01      Utilisateur: xxxxxxxxx     Numéro . . . :   158734 
 
   > call xxxxxxxx
  >> dspjoblog
 
 
 
 
 
 
 
                                      F10
                                       !
                                       !
                                       !
                                       !                                    Fin 
 Appuyez sur ENTREE pour continuer.    !      
                                       v
 F3=Exit   F5=Réafficher    F10=Messages détaillés      F12=Annuler
 F17=Début    F18=Fin                                                        


|    Changer de couleur
 
                           Affichage de tous les messages    
                                                             Système : -------- 
 Travail :   NANTEV01      Utilisateur: xxxxxxxxx     Numéro . . . :   158734 
 
   > call yyyyyy  <-- (pgm rpg contenant du SQL)
     L'instruction PREPARE P1 a été exécutée.
     Tous les chemins d'accès ont été considérés pour le fichier CLIENTS. 
     Tous les chemins d'accès ont été considérés pour le fichier CDES.
     Chemin d'accès créé à partir du fichier indexé CLIENTL1.
     Fichier CLIENTS traité en position de jonction 1.
     Fichier CDES traité en position de jonction 2.
     ODP créé.
     Groupage utilisé pour la requête.
     Le curseur C1 est activé.
     Conversion de données nécessaire pour FETCH ou SELECT imbriquée.
     1 lignes ont été extraites du curseur C1.
     La ligne n'a pas été trouvée.
                                                                    A suivre... 
 Appuyez sur ENTREE pour continuer.           
 
 F3=Exit   F5=Réafficher    F12=Annuler    F17=Début    F18=Fin


|    Changer de couleur
 
 + V3R60/R20 : une nouvelle fonction pour analyser votre activité BdeD.
 
 
   STRDBMON = démarre le moniteur de base de données, pour un job ou
               pour tous les jobs de la machine.
               (on indique le nom du fichier de sortie).
 
 
   ENDDBMON = arrêt du moniteur et écriture de l'analyse dans le fichier
 
 
 
   Chaque requête est analysée en détail avec :
 
        - liste des fichiers traités
        - options utilisées (jonction, groupage, ....)
        - liste des index examinés (raison du choix ou du refus)
        - nombre d'enregistrements traités
        - consommation CPU, ...
 
            (le fichier modèle est QAQQDBMN )


|    Changer de couleur
 
 Les enregistrements sont identifiés par un code (QQRID)
 
  QQQ1000 informations SQL
 
  QQQ3000 séquence d'arrivée
   " 3001 utilisation d'un index existant
   " 3002 création d'index
   " 3003 tri
   " 3004 utilisation d'un fichier temporaire
   " 3005 fichier verrouillé
   " 3006 Chemin d'accès reconstruit
   " 3007 timeout de l'optimiseur
 
   " 3008 sous-requête (SELECT dans un WHERE)
   " 3010 utilisation d'une variable HOST
   " 3014 informations générales
   " 3018 STRDBMON/ENDDBMON
   " 3019 détail
 
 
remarquons les zones suivantes :


|    Changer de couleur
 
 QQRIDX (15,0) nombre d'index créés
 
 QQIDXA        suggestion d'index
 QQIDXD          "          "     détail (liste des clés)
 
 QQC21         méthode de jointure   NL = Nested loop Join
                                     MF =  idem mais avec sélection
                                     HJ = Hash Join
 
 QQC12 (QQRID = 3001)  l'index tient en mémoire
 QQC15 ( "      "   )  type d'index  B = B-arbre
                                     C = Contrainte
                                     E = Evi
                                     X = temporaire
 
 QVC1B (QQRID = 3002)  type d'index créé (B ou E)
 
 Pour plus de détails, voyez le chapitre 12 du RedBook :
 
    DB2 UDB for iSeries, Database Performance and Query Optimization 
 





©AF400