% !TEX root = ../main.tex
\subsection{Query a}

\paragraph{Piano di accesso logico della query a}
\begin{center}
  \begin{forest}
      [{$\pi^{b}$ e.Titolo, sw.Url}
          [{$\bowtie$ e.IdEdizione = sw.IdEdizione}
              [{$\sigma$e.Titolo $>=$'G' $\wedge$ e.Titolo $<$ 'H'}
                  [Edizioni e]
              ]
              [SitiWeb sw]
          ]
      ]
  \end{forest}
\end{center}

\paragraph{Piano di accesso fisico della query a senza indici}
\begin{center}
  \begin{forest}
      [{Project(\{e.Titolo, sw.Url\})}
          [{SortMerge(e.IdEdizione = sw.IdEdizione)}
              [{Sort(\{e.IdEdizione\})}
                  [{Project(\{e.Titolo, e.IdEdizione\})}
                    [{Filter(e.Titolo $>=$ 'G' AND e.Titolo $<$ H)}
                      [{TableScan(Edizioni e)}]
                    ]
                  ]
              ]
              [{Sort(\{sw.IdEdizione\})}
                [{Project(\{sw.Url, sw.IdEdizione\})}
                  [{TableScan(SitiWeb sw)}]
                ]
              ]
          ]
      ]
  \end{forest}
\end{center}

\paragraph{Piano di accesso fisico della query a con due indici}
\begin{center}
  \begin{forest}, baseline, qtree
      [{Project(\{e.Titolo, sw.Url\})}
          [{IndexNestedLoop(e.IdEdizione = sw.IdEdizione)}
              [{IndexFilter(Edizioni e, IndETit,\\ e.Titolo $>=$ 'G' AND e.Titolo $<$ H)}]
              [{IndexFilter(SitiWeb sw, IndSWIdEd,\\ e.IdEdizione = sw.IdEdizione)}]
          ]
      ]
  \end{forest}
\end{center}
Indici necessari: \texttt{IndETit} (indice della tabella Edizioni sull’attributo Titolo) e \texttt{IndSWIdEd} (indice della tabella SitiWeb sulla chiave IdEdizione).

\subsection{Query b}
\paragraph{Piano di accesso logico della query b}
\begin{center}
  \begin{forest}
      [{$\tau$(\{$-$TempoTotaleLettura\})}
          [{$\pi^{b}$ v.IdUtente, SUM(v.TempoLettura) TempoTotaleLettura}
            [{$\sigma$ SUM(v.TempoLettura) $>$ 10}
              [{\{v.IdUtente\} $\gamma$ \{SUM(v.TempoLettura)\}}
                [{$\sigma$ v.TempoLettura $<$ 60}
                  [{Visite v}]
                ]
              ]
            ]
          ]
      ]
  \end{forest}
\end{center}
L’output dell’operatore $\gamma$ è già proiettato sulle sole dimensioni di analisi e risultati delle
funzioni di aggregazione, non occorrerebbe proiettare su \texttt{\{v.IdUtente, SUM(v.TempoLettura)\}}; lo faccio per poter rinominare in TempoTotaleLettura il risultato della SUM.

Nella $\tau$, l’ordinamento discendente è reso dal segno `$-$' per convenzione (in questo caso comunque il tipo è numerico).

\paragraph{Piano di accesso fisico della query b senza indici}
\begin{center}
  \begin{forest}
      [{Sort(\{$-$TempoTotaleLettura\})}
        [{Project(\{v.IdUtente, SUM(v.TempoLettura) TempoTotaleLettura\})}
          [{Filter(SUM(v.TempoLettura) $>$ 10)}
            [{GroupBy(\{v.IdUtente\}, \{SUM(v.TempoLettura)\})}
              [{Sort(\{v.IdUtente\})}
                [{Project(\{v.IdUtente, v.TempoLettura\})}
                  [{Filter(v.TempoLettura $<$ 60)}
                    [{TableScan(Visite v)}]
                  ]
                ]
              ]
            ]
          ]
        ]
      ]
  \end{forest}
\end{center}

\clearpage
\paragraph{Piano di accesso fisico della query b con indici}
\begin{center}
  \begin{forest}, baseline, qtree
    [{Sort(\{$-$TempoTotaleLettura\})}
      [{Project(\{v.IdUtente, SUM(v.TempoLettura) TempoTotaleLettura\})}
        [{GroupBy(\{v.IdUtente\}, \{SUM(v.TempoLettura)\})}
            [{\sout{Project(\{v.IdUtente, v.TempoLettura\})}}
                [{IndexFilter(Visite v, IndVIdUt, v.TempoLettura $<$ 60)}
                ]
              ]
            ]
          ]
        ]
      ]
    ]
  \end{forest}
\end{center}
Indice necessario: \texttt{IndVIdUt} (indice della tabella Visite sull’attributo IdUtente).

Non occorre ordinare prima di raggruppare: l’output di IndexFilter è già ordinato sull’insieme di attributi dell’indice (in questo caso \texttt{\{v.IdUtente\}}), che coincide nel nostro caso con l’insieme delle dimensioni di analisi.

Non occorre nemmeno proiettare su \texttt{\{v.IdUtente, v.TempoLettura\}} prima del raggruppamento, in quanto la groupby può ricevere il record direttamente dalla IndexFilter e scartare gli attributi non rilevanti (cioè quelli che non sono dimensione di analisi né input delle funzioni di aggregazione).
\subsection{Query c}
\paragraph{Piano di accesso logico della query c}
\begin{center}
  \begin{forest}, baseline, qtree
    [{$\pi$ a.IdArticolo, a.Titolo, COUNT(*) NumeroVisite,\\SUM(v.TempoLettura) TempoTotaleLettura}
      [{$\sigma$ COUNT(*) $>=$ 3}
        [{\{a.IdArticolo, a.Titolo\} $\gamma$ \{COUNT(*), SUM(v.TempoLettura)\}}
          [{$\bowtie$ a.IdArticolo = v.IdArticolo}
            [{$\sigma$ a.Premium = 'N'}
              [{Articoli a}]
            ]
            [{Visite v}]
          ]
        ]
      ]
    ]
  \end{forest}
\end{center}
\clearpage
\paragraph{Piano di accesso fisico della query c senza indici}
\begin{center}
  \begin{forest}, baseline, qtree
    [{Project(\{a.IdArticolo, a.Titolo, COUNT(*) NumeroVisite,\\SUM(v.TempoLettura) TempoTotaleLettura\})}
      [{Filter(COUNT(*) $>=$ 3)}
        [{GroupBy(\{a.IdArticolo, a.Titolo\}, \{COUNT(*), SUM(v.TempoLettura)\})}
          [{SortMerge(a.IdArticolo = v.IdArticolo)}
            [{Sort(a.IdArticolo)}
              [{Project(\{a.IdArticolo, a.Titolo\})}
                [{Filter(a.Premium = 'N')}
                  [{TableScan(Articoli a)}]
                ]
              ]
            ]
            [{Sort(v.IdArticolo)}
              [{Project(\{v.IdArticolo, v.TempoLettura\})}
                [{TableScan(Visite v)}]
              ]
            ]
          ]
        ]
      ]
    ]
  \end{forest}
\end{center}
L’output di SortMerge è già ordinato per a.IdArticolo e, dato che \texttt{a.IdArticolo $\to$ a.Titolo},
non occorre ordinare prima della groupby.

\paragraph{Piano di accesso fisico della query c con due indici}
\begin{center}
  \begin{forest}, baseline, qtree
    [{Project(\{a.IdArticolo, a.Titolo, COUNT(*) NumeroVisite,\\SUM(v.TempoLettura) TempoTotaleLettura\})}
      [{Filter(COUNT(*) $>=$ 3)}
        [{GroupBy(\{a.IdArticolo, a.Titolo\}, \{COUNT(*), SUM(v.TempoLettura)\})}
          [{IndexNestedLoop(a.IdArticolo = v.IdArticolo)}
            [{Project(\{a.IdArticolo, a.Titolo\})}
              [{IndexFilter(Articoli a,\\ IndAIdA, a.Premium = 'N')}
              ]
            ]
            [{Project(\{v.IdArticolo, v.TempoLettura\})}
                [{IndexFilter(Visite v,\\IndVIdA, v.IdArticolo = a.IdArticolo)}]
              ]
          ]
        ]
      ]
    ]
  \end{forest}
\end{center}
Indici necessari: IndAIdA (indice della tabella Articoli sull’attributo IdArticolo), IndVIdA (indice
della tabella Visite sull’attributo IdArticolo).
Non occorre fare un ordinamento sull’output della IndexNestedLoop: avendo ricevuto input
ordinato su IdArticolo dalla IndexFilter, e sapendo che \texttt{a.IdArticolo $\to$ a.Titolo}, l’input
della groupby è già raggruppato per le dimensioni di analisi.
