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