269
8.3 Optimisation du code SQL
qu’avec la fonction, nous forçons SQL Server à utiliser la stratégie de requête que
nous avons décidée. Pour chaque ligne de la table Person.Contact impliquée dans la
requête, SQL Server doit entrer dans la fonction et exécuter la requête qui s’y trouve
à nouveau. Puisque nous avons séparé le code en deux objets, l’optimiseur n’a aucun
moyen de lier les deux requêtes pour comprendre ce qu’on veut obtenir. Ainsi la
nature déclarative du langage SQL est violée. En revanche, en incluant avec une
sous-requête les deux opérations dans la même requête, l’optimiseur a tout en main
pour la décortiquer, la comprendre, et l’optimiser. Regardons le plan d’exécution (un
peu nettoyé pour faciliter sa lecture) de l’ordre utilisant la sous-requête :
|--Compute Scalar
|--Hash Match(Right Outer Join ...)
|--Compute Scalar ...
|
|--Stream Aggregate( … Count(*)))
|
|--Index Scan(OBJECT:(...
[nix$Person_Contact$LastName]), ...)
|--Clustered Index Scan(OBJECT:(...
[PK_Contact_ContactID] AS [t]))
La conclusion est simple : méfiez-vous des fonctions.
Comptage des lignes d’une table
Pour compter le nombre total de lignes d’une table, vous n’êtes pas obligé de faire un
COUNT. Vous pouvez vous appuyer sur les informations de métadonnées, qui sont,
autant que nous avons pu en faire l’expérience, toujours à jour. Évidemment, cette
astuce n’est valable que si vous voulez la cardinalité de toute la table, non filtrée.
Démonstration :
SELECT COUNT(*)
FROM Person.Contact;
GO
SELECT SUM(row_count) as row_count
FROM sys.dm_db_partition_stats
WHERE
object_id=OBJECT_ID('Person.Contact') AND
(index_id=0 or index_id=1);
GO
Résultat en reads :
Table 'Contact'. Scan count 1, logical reads 46, … -- COUNT(*)
Table 'sysidxstats'. Scan count 2, logical reads 4, …
-- sys.dm_db_partition_stats
Plan d’exécution : figure 8.13.
8.3 Optimisation du code SQL
qu’avec la fonction, nous forçons SQL Server à utiliser la stratégie de requête que
nous avons décidée. Pour chaque ligne de la table Person.Contact impliquée dans la
requête, SQL Server doit entrer dans la fonction et exécuter la requête qui s’y trouve
à nouveau. Puisque nous avons séparé le code en deux objets, l’optimiseur n’a aucun
moyen de lier les deux requêtes pour comprendre ce qu’on veut obtenir. Ainsi la
nature déclarative du langage SQL est violée. En revanche, en incluant avec une
sous-requête les deux opérations dans la même requête, l’optimiseur a tout en main
pour la décortiquer, la comprendre, et l’optimiser. Regardons le plan d’exécution (un
peu nettoyé pour faciliter sa lecture) de l’ordre utilisant la sous-requête :
|--Compute Scalar
|--Hash Match(Right Outer Join ...)
|--Compute Scalar ...
|
|--Stream Aggregate( … Count(*)))
|
|--Index Scan(OBJECT:(...
[nix$Person_Contact$LastName]), ...)
|--Clustered Index Scan(OBJECT:(...
[PK_Contact_ContactID] AS [t]))
La conclusion est simple : méfiez-vous des fonctions.
Comptage des lignes d’une table
Pour compter le nombre total de lignes d’une table, vous n’êtes pas obligé de faire un
COUNT. Vous pouvez vous appuyer sur les informations de métadonnées, qui sont,
autant que nous avons pu en faire l’expérience, toujours à jour. Évidemment, cette
astuce n’est valable que si vous voulez la cardinalité de toute la table, non filtrée.
Démonstration :
SELECT COUNT(*)
FROM Person.Contact;
GO
SELECT SUM(row_count) as row_count
FROM sys.dm_db_partition_stats
WHERE
object_id=OBJECT_ID('Person.Contact') AND
(index_id=0 or index_id=1);
GO
Résultat en reads :
Table 'Contact'. Scan count 1, logical reads 46, … -- COUNT(*)
Table 'sysidxstats'. Scan count 2, logical reads 4, …
-- sys.dm_db_partition_stats
Plan d’exécution : figure 8.13.
