Gestion des index SQL : Soyez AWARE !

Post on 09-Jul-2015

832 views 3 download

transcript

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