Newsletter 4/2013
Transcription
Newsletter 4/2013
SWISS ORACLE USER GROUP www.soug.ch N e ws le t ter 4/2013 Oktober 2013 · Oracle 12c Consolidation Planer · Data Redaction & Transparent Sensitive Data Protection · Oracle Forms Migration · Oracle 12c “IDENTITY table clause” Feature und APEX 28 TIPS&TECHNIQUES Nicolas Jardot, dbi services Cas pratique Oracle 12c : Améliorations pour les histogrammes sur une colonne de type varchar2. L’ « optimizer » Oracle se base sur les statistiques disponibles sur les objets pour définir les plans d’exécutions des requêtes. Les histogrammes fournissent au moteur une meilleure idée de la distribution des données et sont systématiquement utilisés lorsqu’il y en a. SQL> select count(*), count(distinct R_FOLDER_PATH) from DM_ Voyons la distribution des données : FOLDER_R; COUNT(*) COUNT(DISTINCT R_FOLDER_PATH) ---------- -----------------------------10455646 1486126 SQL> select count(*) from DM_FOLDER_R where R_FOLDER_PATH is null; COUNT(*) ---------8969518 Par défaut, Oracle va essayer de déterminer automatiquement quelles colonnes ont besoin d’histogrammes et les calculer. Le problème, c’est que ce comportement peut poser des problèmes sur les colonnes de type texte. Nous allons voir pourquoi Limitation en Oracle 11g Oracle considère seulement les 32 premiers caractères lors du calcul d’un histogramme sur une colonne de type varchar2. Donc pour Oracle, il y a un grand nombre de lignes ‘identiques’ : et comment la prochaine version d’Oracle nous évitera des soucis dans un cas concret. Contexte J’ai rencontré ce problème chez un client qui utilise un système de gestion documentaire bien connu. Le système stocke dans une table l’emplacement des fichiers : SQL> desc USER.DM_FOLDER_R Name -------------------R_OBJECT_ID I_POSITION R_FOLDER_PATH I_ANCESTOR_ID Null? -------NOT NULL NOT NULL Type ---------------------------VARCHAR2(16) NUMBER(6) VARCHAR2(740) VARCHAR2(16) La colonne R_FOLDER_PATH contient des chemins pointant vers les documents sur les disques dédiés au stockage et le système utilise une requête pour chercher l’objet correspondant à un chemin donné : SQL> select * from ( select substr(R_FOLDER_PATH,1,32) path , count(*) from DM_FOLDER_R group by substr(R_FOLDER_PATH,1,32) having count(*) > 100 order by 2 desc) where rownum <=5; PATH COUNT(*) ----------------------------------- ---------8969518 /Resources/Evaluation Objects/16 126835 /USERS Projects/L/PROJCOD/USERS 41255 /USERS Projects/S/PROJCOD/USERS 33113 /USERS Projects/R/PROJCOD/USERS 24492 5 rows selected. SQL> exec dbms_stats.gather_table_stats(USER,'DM_FOLDER_R'); SQL> select table_name, column_name, histogram, num_buckets from user_tab_columns where table_name = 'DM_FOLDER_R'; TABLE_NAME --------------DM_FOLDER_R DM_FOLDER_R DM_FOLDER_ DM_FOLDER_R COLUMN_NAME ------------------R_OBJECT_ID I_POSITION R_FOLDER_PATH I_ANCESTOR_ID HISTOGRAM NUM_BUCKETS ---------------- ----------NONE 1 NONE 1 HEIGHT BALANCED 254 NONE 1 SQL> select R_OBJECT_ID from DM_FOLDER_R where R_FOLDER_PATH = :p0 A cause de la hiérarchie des répertoires, on a une grande partie des enregistrements avec les premiers caractères identiques, tout en ayant des valeurs quasiment distinctes en réalité (pour les valeurs non nulles). SOUG Newsletter 4/2013 Oracle a généré un histogramme de type « HEIGHT BALANCED » sur la colonne « R_FOLDER_PATH ». Un histogramme de ce type est crée quand il y a plus de 254 valeurs distinctes. Oracle découpe le nombre de valeurs en intervalles contenant environ le même nombre de lignes. Plus la valeur est populaire plus l’intervalle est grand. Lors de l’évaluation des cardinalités, l’ « optimizer » va utiliser les valeurs de l’histogramme. Lors de l’exécution de la requête, Oracle va estimer le nombre de lignes retournées par la condition et calculer le coût des différentes opérations. TIPS&TECHNIQUES 29 SQL_ID 2w925nfz6y65k, child number 0 ------------------------------------select R_OBJECT_ID from DM_FOLDER_R where R_FOLDER_PATH=:p0 Plan hash value: 709641409 ---------------------------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time | ---------------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | || | 21056 (100) | | 1399K | 21056 (1) | 00:03:31 | |* 1 | TABLE ACCESS FULL | DM_FOLDER_R | 40956 ---------------------------------------------------------------------------------------------------------------- En utilisant l’histogramme, Oracle estime qu’il y a 40956 lignes qui correspondent et choisit de lire toute la table car c’est le plan avec le coût le plus faible. Le coût estimé pour les I/O dépend des statistiques systèmes présentes dans la base. Comportement en Oracle 12c Oracle a ajouté plusieurs fonctionnalités et modifications au mécanisme de calcul des statistiques avec la 12c. Il y a une modification qui n’est pas dans la liste des changements, que nous allons voir maintenant Reprenons la même table dans les mêmes conditions avec une base en 12.1.0.1 : SQL> exec dbms_stats.gather_table_stats(USER,'DM_FOLDER_R'); SQL> select table_name, column_name, histogram, num_buckets from user_tab_columns where table_name = 'DM_FOLDER_R'; TABLE_NAME -------------------DM_FOLDER_R DM_FOLDER_R DM_FOLDER_R DM_FOLDER_R COLUMN_NAME -------------------I_ANCESTOR_ID R_FOLDER_PATH I_POSITION R_OBJECT_ID HISTOGRAM NUM_BUCKETS --------------- ----------NONE 1 NONE 1 NONE 1 NONE 1 Cette fois, Oracle n’a pas calculé d’histogramme pour la colonne. La limite de 32 caractères a été enlevée. Cela a permis à Oracle de ne plus considérer les valeurs comme identiques et avec autant de valeur uniques, l’histogramme n’a plus d’intérêt. Regardons le plan d’exécution de la même requête : SQL_ID 2w925nfz6y65k, child number 0 ------------------------------------select R_OBJECT_ID from DM_FOLDER_R where R_FOLDER_PATH=:p0 Plan hash value: 2640530187 ---------------------------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time | ---------------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | 5 (100) | | | 1 | TABLE ACCESS | | | | | | | | BY INDEX ROWID BATCHED | DM_FOLDER_R | 1 | 35 | 5 (0) | 00:00:01 | |* 2 | INDEX RANGE SCAN | D_1F0095A880000015 | 1 | | 4 (0) | 00:00:01 | ---------------------------------------------------------------------------------------------------------------- Sans histogramme, Oracle estime qu’une seule ligne sera retournée car les valeurs non nulles sont distinctes. Pour ce cas, Oracle choisit donc un plan d’exécution utilisant l’index qui est plus efficace. SOUG Newsletter 4/2013 30 TIPS&TECHNIQUES Y-a-t-il une nouvelle limite ? Créons simplement une table avec 4 colonnes, avec des textes qui commencent avec un certain nombre de caractères identiques (16, 32, 64 et 128) : SQL> create table test_hist as select rpad('long_string_16',16,'x') || rownum st16, rpad('long_string_32',32,'x') || rownum st32, rpad('long_string_64',64,'x') || rownum st64, rpad('long_string_128',128,'x') || rownum st128 from dual connect by level <= 10; Table created. Il y a 10 lignes uniques dans la table, Oracle doit pouvoir créer un histogramme de type « FREQUENCY » avec 10 valeurs. Ce type d’histogramme permet de donner le nombre d’occurrence d’une valeur donnée. Forçons le calcul des histogrammes pour cette table : Conclusion SQL> exec dbms_stats.gather_table_stats(ownname=>USER,tabname=>'T EST_HIST', method_opt=>'FOR ALL COLUMNS SIZE 10'); PL/SQL procedure successfully completed. Vérifions le nombre de valeurs : SQL> select table_name, column_name, histogram, num_buckets from user_tab_columns where table_name = 'TEST_HIST'; TABLE_NAME -------------------TEST_HIST TEST_HIST TEST_HIST TEST_HIST COLUMN_NAME -------------ST128 ST64 ST32 ST16 HISTOGRAM --------------FREQUENCY FREQUENCY FREQUENCY FREQUENCY NUM_BUCKETS ----------1 1 10 10 Ce problème a eu lieu sur une base de production avec une table de 10 millions de lignes après que le job automatique ait rafraichi les statistiques. Il y a eu un impact significatif sur les performances de l’application. Cette « petite » amélioration, non documentée, permet de résoudre un problème qui n’avait qu’une solution de contournement, qui était de supprimer l’histogramme. Avec le temps, Oracle rend de plus en plus efficace le calcul des statistiques avec l’objectif de donner à son moteur les meilleures estimations possibles pour obtenir le plan d’exécution le plus rapide. Q Oracle n’a pas pu différencier les valeurs lorsque les 64 premiers caractères sont identiques, la nouvelle limite est entre 32 et 64 au lieu de 32. Sources Statistics and histograms of character columns with length longer than 32 bytes (Doc ID 800089.1) Bug 9885553 – DBMS_STATS produces incorrect column NDV distinct values statistics (Doc ID 9885553.8) Contact dbi services Nicolas Jardot E-Mail: [email protected] SOUG Newsletter 4/2013