Gestion des index SQL : Soyez AWARE ! Antonio Gomes Rodrigues
Gestion des index SQL : Soyez AWARE !
Antonio Gomes Rodrigues
Antonio Gomes Rodrigues@ra0077
Consultant chez Aliecom
Rédacteur pour developpez.com
Conférencier 0
Gestion des index SQL : Soyez AWARE !
Pourquoi optimiser les index
Attention
Un peu de théorie
Quiz
Méthodologie
Et si cela ne suffit pas ?
Conclusion
Gestion des index SQL : Soyez AWARE !
Pourquoi optimiser les index
Attention
Un peu de théorie
Quiz
Méthodologie
Et si cela ne suffit pas ?
Conclusion
Pourquoi optimiser les index
Les problèmes de bases de données sont régulièrement dans le top 5 des problèmes de performance d'une application Java
Pourquoi optimiser les index
JPA/Hibernate, Spring JDBC et JDBC ont pour point commun de générer des requêtes SQL
Pourquoi optimiser les index
Gestion des index SQL : Soyez AWARE !
Pourquoi optimiser les index
Attention
Un peu de théorie
Quiz
Méthodologie
Et si cela ne suffit pas ?
Conclusion
Attention : DBA, c'est un métier
Gestion des index SQL : Soyez AWARE !
Pourquoi optimiser les index
Attention
Un peu de théorie
Quiz
Méthodologie
Et si cela ne suffit pas ?
Conclusion
Théorie : Etude de cas
Théorie : Un index, c'est quoi ?
Théorie : Un index, c'est quoi ?
Représentation triée des éléments indexés à l'aide d'un arbre équilibré
Théorie : Un index, c'est quoi ?
Théorie : Un index, comment ça marche ?
Théorie : Plan d'execution
explain plan for select nom,prenom from clients where sex = 'MALE'
select * from table(dbms_xplan.display)
Plan hash value: 4036073249
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 500 | 11000 | 9 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| CLIENTS | 500 | 11000 | 9 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("SEX"='MALE')
Théorie : Plan d'execution
Théorie : Plan d'execution
Théorie : Plan d'execution
Théorie : Plan d'execution
Théorie : Plan d'execution
Théorie : Plan d'execution
Théorie : Plan d'execution
Théorie : Plan d'execution
Théorie : Plan d'execution
Théorie : CBO
Et comment le plan d'exécution est décidé ?
Théorie : CBO
CBO = Cost Based Optimizer
Théorie : Info sur les index d'une table
select index_name, index_type, uniqueness
from user_indexes
where table_name = 'CLIENTS';
Gestion des index SQL : Soyez AWARE !
Pourquoi optimiser les index
Attention
Un peu de théorie
Quiz
Méthodologie
Et si cela ne suffit pas ?
Conclusion
Quiz 1 : ?
Quiz 1 : Explication
Re équilibrer l'arbre
Ecrire à au moins deux endroits (table et index)
Quiz 1 : ?
Quiz 1 : Explication
Plus d'index != meilleur perf
Il suffit d'un seul
Quiz 1: Nombre d'index
Plus d'index != plus de performance
Et donc il faut trouver le bon index
Making of
http://blog.aliecom.com/pourquoi-il-faut-faire-attention-au-nombre-dindex-sql/
Quiz 2 : ?
create table CLIENTS ....
create index pk_clients on clients(id_client)
select id_client from clients where id_client = '5'
L'index est il utilisé ?
Quiz 2 : Réponse
Non
Quiz 2 : Explication
Index sur clé primaire crée automatiquement dans Oracle.
SQL> create index pk_clients on clients(id_client);
ERROR at line 1:
ORA-01408: such column list already indexed
Quiz 2 : Index par défaut
Be aware sur la politique de création d'index par défaut
Quiz 3 : ?
create index ix_clientx_pays on clients(pays)
select nom,prenom from clients where upper(pays) = 'UNITED STATES'
Pourquoi l'index n'est pas utilisé ?
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 99K| 9 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| CLIENTS | 1000 | 99K| 9 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Quiz 3 : Indice
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 99K| 9 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| CLIENTS | 1000 | 99K| 9 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
1 - filter(UPPER("PAYS")='UNITED STATES')
Quiz 3 : Explication
Quiz 3 : Solution
create index ix_clientx_pays2 on clients(upper(pays))
Quiz 3 : Solution
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10 | 1020 | 5
| 1 | TABLE ACCESS BY INDEX ROWID| CLIENTS | 10 | 1020 | 5
|* 2 | INDEX RANGE SCAN | IX_CLIENTX_PAYS2 | 4 | | 4
--------------------------------------------------------------------------------
Quiz 3 : ?
create index ix_clientx_sex on clients(sex)
select nom,prenom from clients where UPPER(sex) = 'MALE'
L'index est il utilisé ?
Quiz 3 : Indice
Quiz 3 : Réponse
Non
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10 | 220 | 9 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| CLIENTS | 10 | 220 | 9 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Quiz 3 : Index de fonction
Be aware lors de l'utilisation de fonction dans les requêtes SQL
Quiz 4 : ?
create index ix_clientx_sex on clients(sex)
select nom,prenom from clients where sex is null
Pourquoi l'index n'est pas utilisé ?
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 22000 | 48 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| CLIENTS | 1000 | 22000 | 48 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("SEX" IS NULL)
Quiz 4 : Explication
Quiz 4 : Solution
CREATE INDEX index_null ON clients (sex, '1')
Quiz 4 : Solution
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 22000 | 32 (0)| 00:00:01
| 1 | TABLE ACCESS BY INDEX ROWID| CLIENTS | 1000 | 22000 | 32 (0)| 00:00:01
|* 2 | INDEX RANGE SCAN | INDEX_NULL | 1000 | | 4 (0)| 00:00:01
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("SEX" IS NULL)
Quiz 4 : Indexer les null
Be aware à ne pas oublier les contraintes dans le schéma de bdd
Be aware aux valeurs null
Bien connaitre sin serveur de bdd
Quiz 5 : ?
create index clients_identifiant_unique_ix on clients(identifiant_unique);
select id_client from clients where identifiant_unique like '109876545210387';
Existe t il un meilleur index ?
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 |
| 1 | TABLE ACCESS BY INDEX ROWID| CLIENTS | 1 |
|* 2 | INDEX RANGE SCAN | CLIENTS_IDENTIFIANT_UNIQUE_IX | 4 |
--------------------------------------------------------------------------------
Quiz 5 : Indice
create index clients_identifiant_unique_ix on clients(identifiant_unique)
select id_client from clients where identifiant_unique like '109876545210387'
Quiz 5 : Explication
Quiz 5 : Solution
create unique index clients_identifiant_unique_ix on clients(identifiant_unique)
Quiz 5 : Solution
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 22 |
| 1 | TABLE ACCESS BY INDEX ROWID| CLIENTS | 1 | 22 |
|* 2 | INDEX UNIQUE SCAN | CLIENTS_IDENTIFIANT_UNIQUE_IX | 1 | |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("IDENTIFIANT_UNIQUE"='109876545210387')
Quiz 5 : Index unique
Be aware lors de la création du schéma de la base de données
Si un champ est unique, le dire à Oracle
Quiz 6 : ?
create index ix_clientx_sex on clients(sex)
select nom,prenom from clients where sex = 'MALE'
Pourquoi l'index n'est pas utilisé ?
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 510 | 11220 | 9 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| CLIENTS | 510 | 11220 | 9 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("SEX"='MALE')
Quiz 6 : Indice
CBO = Cost Based Optimizer
Quiz 6 : Explication
select count(*) from clients where sex = 'MALE'
-> 51% des lignes
Quiz 6 : Preuve
Si on change la répartition (de 51% à 8,5%)
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 511 | 11753 | 18 (0)|
| 1 | TABLE ACCESS BY INDEX ROWID| CLIENTS | 511 | 11753 | 18 (0)|
|* 2 | INDEX RANGE SCAN | IX_CLIENTX_SEX | 511 | | 3 (0)|
--------------------------------------------------------------------------------
Quiz 6 : Répartition des données
Be aware sur la validité d'un index au cours de sa vie
Superviser votre serveur de base de données
Quiz 7 : ?
create index ix_clientx_sex on clients(sex)
select nom,prenom from clients where sex is null
L'index est il utilisé ?
Quiz 7 : Indice
Quiz 7 : Explication
Quiz 7 : Moteur de base de données
Be aware sur les possibilitées du serveur de bases de données utilisés
Be aware sur le contexte des astuces trouvées sur Internet
Quiz 8 : ?
create index ix_clientx_sex on clients(sex)
# Ajout de données dans la table clients
select nom,prenom from clients where sex = 'MALE'
Pourquoi l'index n'est pas utilisé ?
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 510 | 11220 | 9 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| CLIENTS | 510 | 11220 | 9 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Quiz 8 : Indice
CBO = Cost Based Optimizer
Quiz 8 : Explication
CBO se base sur des données obsolètes pour faire le choix du plan d'exécution de la requête
Quiz 8 : Solution
EXEC dbms_stats.gather_table_stats('SYSTEM','Clients',cascade=>TRUE);
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 511 | 11753 | 18 (0)|
| 1 | TABLE ACCESS BY INDEX ROWID| CLIENTS | 511 | 11753 | 18 (0)|
|* 2 | INDEX RANGE SCAN | IX_CLIENTX_SEX | 511 | | 3 (0)|
--------------------------------------------------------------------------------
Quiz 8 : Statistiques
Ne pas oublier de faire régulièrement des update stat
Ne pas oublier de faire des update stats après un gros changement de données (update, insert, delete)
Quiz 9 : ?
create index clients_nom_ix on clients(nom)
select nom, prenom from clients where nom like 'A%'
Existe t il un meilleur index ?
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 37 | 2516 | 8
| 1 | TABLE ACCESS BY INDEX ROWID| CLIENTS | 37 | 2516 | 8
|* 2 | INDEX RANGE SCAN | CLIENTS_NOM_IX | 9 | | 2
--------------------------------------------------------------------------------
Quiz 9 : Indice
Quiz 9 : Solution
create index clients_nom_prenom_ix on clients(nom,prenom)
Quiz 9 : Solution
create index clients_nom_prenom_ix on clients(nom,prenom)
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 38 | 570 | 2 (0)|
|* 1 | INDEX RANGE SCAN| CLIENTS_NOM_PRENOM_IX | 38 | 570 | 2 (0)|
--------------------------------------------------------------------------------
Quiz 9 : Index couvrant
Be aware de l'existence des index couvrants
Be aware au coût de gestion d'un index couvrant
Quiz 10 : ?
create index clients_id_unique_nom_ix on clients(identifiant_unique,nom)
select nom from clients where identifiant_unique like '%1'
Pourquoi l'index n'est pas utilisé ?
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5000 | 117K| 701 (1)| 00:00:09 |
|* 1 | TABLE ACCESS FULL| CLIENTS | 5000 | 117K| 701 (1)| 00:00:09 |
-----------------------------------------------------------------------------
Quiz 10 : Explication
Quiz 10 : Solution
create index rev_clients_id_unique_nom_ix on clients(reverse(identifiant_unique),nom)
select nom from clients where reverse(identifiant_unique) like '1%'
Quiz 10 : Accès aux données
Be aware lors de l'écriture des requêtes
Quiz 11 : ?
create index ix_clients_num_rue on clients(numero_de_rue)
select nom, prenom from clients where numero_de_rue = 1
Pourquoi l'index n'est pas utilisé ?
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20 | 360 | 9 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| CLIENTS | 20 | 360 | 9 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Quiz 11 : Indice
Quiz 11 : Indice
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20 | 360 | 9 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| CLIENTS | 20 | 360 | 9 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
1 - filter(TO_NUMBER("NUMERO_DE_RUE")=1)
Quiz 11 : Explication
Oracle fait une conversion automatique
Quiz 11 : Solution
select nom, prenom from clients where numero_de_rue = '1'
Quiz 11 : Conversion automatique
Be aware aux conversions automatiques
Be aware lors de la création du schéma de bdd
Quiz 12 : ?
create index achats_prix_ix on achats(prix);
select count(*) from achats where prix + 10 = 500
Pourquoi l'index n'est pas utilisé ?
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 4 | 43 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 4 | | |
|* 2 | TABLE ACCESS FULL| ACHATS | 100 | 400 | 43 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Quiz 12 : Explication
Quiz 12 : Solution
select count(*) from achats where prix = 500 - 10
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 4 | 1 (0)|
| 1 | SORT AGGREGATE | | 1 | 4 | |
|* 2 | INDEX RANGE SCAN| ACHATS_PRIX_IX | 13 | 52 | 1 (0)|
--------------------------------------------------------------------------------
Quiz 12 : Accès aux données
Be aware lors de l'écriture des requêtes
Quiz 13 : ?
A : select count(*) from achats
B : select count(1) from achats
Quel est la requête la plus rapide ?
Quiz 13 : Solution
select count(*) from achats
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 516 (1)| 00:00:07 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| SYS_C007034 | 985K| 516 (1)| 00:00:07 |
-----------------------------------------------------------------------------
select count(1) from achats
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 516 (1)| 00:00:07 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| SYS_C007034 | 985K| 516 (1)| 00:00:07 |
-----------------------------------------------------------------------------
Quiz 13 : Astuces sur Internet
Méfiez vous des "astuces" trouvées sur Internet
Mesurez, ne devinez pas
Quiz 14 : ?
create index achats_p_id on achats(prix,id_achat)
select prix,id_achat from achats where prix > 30 order by prix asc,id_achat desc
Existe t il un meilleur index ?
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 963K| 9411K| | 4629 (2)|
| 1 | SORT ORDER BY | | 963K| 9411K| 18M| 4629 (2)|
|* 2 | INDEX FAST FULL SCAN| ACHATS_P_ID | 963K| 9411K| | 764 (2)|
-------------------------------------------------------------------------------------
Quiz 14 : Indice
Index = Représentation triée des éléments indexés à l'aide d'un arbre équilibré
Quiz 14 : Indice
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 963K| 9411K| | 4629 (2)|
| 1 | SORT ORDER BY | | 963K| 9411K| 18M| 4629 (2)|
|* 2 | INDEX FAST FULL SCAN| ACHATS_P_ID | 963K| 9411K| | 764 (2)|
-------------------------------------------------------------------------------------
create index achats_p_id on achats(prix,id_achat)
select prix,id_achat from achats where prix > 30 order by prix asc,id_achat desc
Quiz 14 : Solution
create index achats_p_id2 on achats(prix asc,id_achat desc)
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 963K| 9411K| 2827 (1)| 00:00:34 |
|* 1 | INDEX RANGE SCAN| ACHATS_P_ID2 | 963K| 9411K| 2827 (1)| 00:00:34 |
---------------------------------------------------------------------------------
Quiz 14 : Ordre des index
Be aware sur l'ordre des index et l'ordre d'accès aux données
Quiz 15 : ?
Pourquoi l'index n'est pas utilisé ?
create index clients_n_ix on clients(nom)
Quiz 15 : Indice
Quiz 15 : Indice
Quiz 15 : ExplicationHibernate:
/* criteria query */ select
this_.ID_CLIENT as ID1_0_0_,
this_.NOM as NOM0_0_,
...
this_.IDENTIFIANT_UNIQUE as IDENTIF17_0_0_
from
SYSTEM.CLIENTS this_
where
lower(this_.NOM)=?
Quiz 15 : Solution
Index de fonction
Ne pas utiliser ilike/ignoreCase()
Contrainte sur les valeurs de la table
Quiz 15 : ORM/Framework
Be aware sur le comportement des librairies utilisées
Gestion des index SQL : Soyez AWARE !
Pourquoi optimiser les index
Attention
Un peu de théorie
Quiz
Méthodologie
Et si cela ne suffit pas ?
Conclusion
Méthodologie
Mesurez, ne devinez pas
Méthodologie
Méthodologie
Avoir plateforme de test réaliste
x 200
select * from t_conducteur left join t_voiture on id_conducteur=conducteur_fk where couleur = 'rouge'
Avoir plateforme de test réaliste
Avoir un volume de données le plus proche possible de celui en production
Avoir plateforme de test réaliste
Avoir plateforme de test réaliste
Avoir un serveur de base de données avec la configuration la plus proche possible de celle en production
Méthodologie
Récupérer les requêtes lentes et fréquentes
Récupérer les requêtes lentes et fréquentes
Récupérer les requêtes lentes et fréquentes
A utiliser plutôt pour tuner le serveur de bases de données
Récupérer les requêtes lentes et fréquentes
Requête par requête ?
Récupérer les requêtes lentes et fréquentes
Requête par requête ?
Récupérer les requêtes lentes et fréquentes
Récupérer les requêtes lentes et fréquentes
Récupérer les requêtes lentes et fréquentes
Méthodologie
Eliminer l'inutile
Une requête rapide = une requête qui n'existe pas
Eliminer l'inutile
Attention aux n+1 select avec les ORM
http://arodrigues.developpez.com/tutoriels/java/performance/hibernate-performance-part1-strategies-chargement/
Eliminer l'inutile
Utiliser des caches
Eliminer l'inutile
Ne récupérer que le nécessaire
select * from clients
Statistics
----------------------------------------------------------
19 329 961 bytes sent via SQL*Net to client
100000 rows processed
select nom,prenom from clients
Statistics
----------------------------------------------------------
2 351 810 bytes sent via SQL*Net to client
100000 rows processed
Eliminer l'inutile
Utiliser avec précaution des PreparedStatement à la place de Statement
Eliminer l'inutile
Purge des données inutiles
Eliminer l'inutile
Séparer les données courantes des données historiques
Méthodologie
Ajout d'index
Sur quoi mettre un index ?
clé étrangère
clause where
index couvrant
order
group by
union
distinct
Gestion des index SQL : Soyez AWARE !
Pourquoi optimiser les index
Attention
Un peu de théorie
Quiz
Méthodologie
Et si cela ne suffit pas ?
Conclusion
Et si cela ne suffit pas ?
Table space
index bitmap
schéma bdd
IOT (Index Organised Table)
Tuning du serveur de base de données
...
Appeler un DBA
Gestion des index SQL : Soyez AWARE !
Pourquoi optimiser les index
Attention
Un peu de théorie
Quiz
Méthodologie
Et si cela ne suffit pas
Conclusion
Conclusion
BE AWARE