• Aucun résultat trouvé

4.4 Problématique des N+1 requêtes

5.4.2 Le modèle de coût

Nous analysons dans cette section le coût associé aux différentes stratégies de matérialisation résultant de l’application des règles de réécriture. Pour ce faire, nous supposons que

• le coût d’exécution de la requête côté serveur est constant et et ne dépend pas de la taille de la requête ;

• le coût de transmission de la requête du serveur au client est indépendant de la taille du tuple. Nous élaborons une série de tests afin de confirmer ces hypothèses, celle-ci sera présentée ultérieure- ment.

5.4.2.1 Le modèle

Nous modélisons le coût du processus d’évaluation de requête comme une combinaison linéaire des trois opérateurs : open, fetch, and decode :

cot= Copen× Nopen+ Crseau× Nf etch+ Cdecode× Ndecode (5.1)

Copen, Crseau, and Cdecodereprésentent le coût relatif à chaque opération. Ces facteurs dépendent

de plusieurs facteurs :

• le langage de programmation ; • la bande passante du réseau ;

• la performance du serveur de bases de données ; • les caractéristiques techniques des machines ; • etc.

L’étude de ces facteurs sera reportée à l’analyse de l’évaluation de performance et nous nous focalisons sur l’estimation de Nopen, Nf etchand Ndecodepour le synopsis d’un programme basique de

la forme : @t1[p1]{@t2[p2]}. Dans ce qui suit, nous notons :

• |t1| (resp. |t2|) : le nombre de tuples de la table t1(resp. t2) dans la trace du synopsis ;

• α : le nombre moyen de tuples de t2 en correspondance avec un tuple de t1(autrement dit, le

nombre moyen d’exécutions de la boucle interne dans le mode de chargement L).

Le tableau 5.1 résume les valeurs de Nopen, Nf etch et Ndecodepour chacune des stratégies : L

Nopen Nf etch Ndecode

L 1+ |t1| |t1| (1+ Max(1, α)) |t1| (1+ α)

S 1 Max(|t1|, α|t1|) |t1| (1+ α)

D 2 |t1|+ |t2| |t1|+ |t2|

T. 5.1 – Analyse des coûts relatifs aux règles de réécriture d’un synopsis de la forme @t1[p1]{@t2[p2]}

5.4.2.2 Explications

1. Le mode L détient le plus grand nombre d’opérations open, étant donné qu’une requête sur t2 est exécutée pour chaque tuple de t1. Le nombre d’opérations fetch est |t1| * (1+ Max(α,

1)). Ceci s’explique par une boucle externe sur t1, puis au moins une opération fetch est opérée

dans la boucle interne, même dans le cas où α= 0 (le cas où il n’y pas de tuples en association avec le tuple courant de t1). Dans ce cas de figure, la première opération fetch exécutée dans la

boucle interne retourne un objet null, qui compte néanmoins comme étant un échange avec le serveur de données. Le nombre d’opérations decode est de |t1| * (1+ α), ce qui s’explique par

le décodage ou la transformation des tuples de la table t1 en forme objets au sein de la boucle

externe, puis le décodage des tuples de t2 qui sont considérés dans la boucle interne et dont la

taille est α*|t1|, sous forme objets.

2. Le mode S opère exactement une opération open, ce qui écarte complètement le problème des N+1 requêtes. Nf etch est égal à Max(|t1|, α|t1|) s’explique par la jointure externe. Le pro-

cessus de matérialisation est identique à celui du mode L. L’opération la plus coûteuse pour cette stratégie réside dans la taille de chaque tuple retourné par l’opération fetch, qui combine à la fois un tuple de t1puis un tuple de t2. Convertir ces tuples en une représentation sous forme

de graphe d’objets n’est pas trivial et nécessite le même nombre d’opérations decode que la stratégie L.

3. La stratégie D récupère séparément t1et les tuples associées de t2, pour un nombre total

de fetch égal à |t1|+ |t2| avec exactement deux opérations open. Chaque tuple est récupéré une

fois et convertit en forme objet d’une manière indépendante.

5.4.2.3 Interprétations

D’après le tableau 5.1, nous pouvons remarquer que les deux stratégies S et D évitent le problème des N+1 requêtes. La différence entre les deux modes réside dans le compromis entre le nombre d’opérations fetch, qui est toujours moindre pour le mode S et le coût de l’opération decode, qui dépend de α. Deux cas de figures se présentent :

1. Si α ∈ [0, 1] : il existe au moins un tuple de t2en association avec un tuple de t1. Dans ce cas,

le coût de l’opération decode est de 2 ∗ |t1| pour le mode S et |t1|+ |t2| < 2 ∗ |t1| pour le

Exemple 8. Considérons le synopsis @customer{@nation} du TPC-H benchmark. Étant donné qu’il existe une association plusieurs-à-un entre la table Customer et Nation, α= 1. Supposons une instance de10, 000 clients et 200 nations.

Le modeS produit une requête de jointure externe entre les deux tables, avec 10, 000 fetch et20, 000 decode. Notons que chaque tuple nation est décodé, en moyenne, 50 fois.

La stratégie D en revanche, exécute 2 requêtes et au plus 10, 200 fetch et decode. Le nombre de fetch est légèrement supérieur au modeS, vu que les clients et les nations sont traités séparément, mais cette stratégie évite néanmoins le décodage redondant des nations. 2. Si α > 1, ils existent, en moyenne, plusieurs tuples de t2en association avec un tuple de t1. Le

coût de decode est |t1| ∗ (1+ α) pour chacune des deux stratégies S et D. Vu que la

première génére un nombre inférieur de fetch, il serait préférable d’opter pour cette stratégie. Exemple 9. Considérons pour cette exemple le synopsis @customer{@orders} du TPC-H benchmark. Vu qu’il existe une association un-à-plusieurs entre les tables Customer et Orders, α > 1. Supposons une instance avec :

(a) 10, 000 clients ; (b) 50, 000 orders ; (c) α= 5.

La stratégieS exécute une requête de jointure externe, avec 50, 000 fetch et 60, 000 de- code. La stratégie D exécute 2 requêtes, 60, 000 fetch et decode. La première stratégie présente un gain de 10,000 fetch et devrait être préférée et considérée.

5.4.2.4 Conclusion

Nous soulevons un point important relatif à la taille du cache localisé en mémoire centrale du client. Ce facteur dépend à la fois du nombre de nœuds qui doivent être stockés dans le cache ainsi que des délais durant lesquels ces données devraient être gardés. Un nœud devrait être sauvegardé tant qu’il est probable qu’il soit requis par l’exécution du programme. Basé sur l’analyse des coûts des différentes stratégies de matérialisation, les directives suivantes peuvent être adoptées :

1. un nœud provenant d’une association plusieurs-à-un devrait être sauvegardé en cache tant que la boucle associé au nœud parent n’est pas achevée : ceci est le cas, par exemple des nœuds de la tableNation.

2. un nœud provenant d’une association un-à-plusieurs ne devrait pas être gardé dans le cache, une fois qu’il a été traité par le programme : ceci est le cas par exemple des nœuds de la table Orders.

Nous élaborons, à présent et suite à ces directives un algorithme d’optimisation relatif aux stratégies de matérialisation et de mise en cache des données.