Queer European MD passionate about IT

piani_di_accesso.tex 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. % !TEX root = ../main.tex
  2. \subsection{Query a}
  3. \paragraph{Piano di accesso logico della query a}
  4. \begin{center}
  5. \begin{forest}, baseline, qtree
  6. [{$\pi^{b}$ r.IdRicetta , r.Nome}
  7. [{$\bowtie$ p.IdPersona = r.IdCreatrice}
  8. [{$\sigma$ p.Nome = 'Giovanni'}
  9. [Persone p]
  10. ]
  11. [Ricette r]
  12. ]
  13. ]
  14. \end{forest}
  15. \end{center}
  16. Non c'è in questo caso differenza tra $\pi^{b}$ e $\pi$: non ci possono essere
  17. duplicati.
  18. \paragraph{Piano di accesso fisico della query a senza indici}
  19. \begin{center}
  20. \begin{forest}, baseline, qtree
  21. [{Project(\{r.IdRicetta , r.Nome\})}
  22. [{SortMerge(p.IdPersona = r.IdCreatrice)}
  23. [{Sort([p.IdPersona])}
  24. [{Project(\{p.IdPersona\})}
  25. [{Filter(p.Nome = 'Giovanni')}
  26. [{TableScan(Persone p)}]
  27. ]
  28. ]
  29. ]
  30. [{Sort([r.IdCreatrice])}
  31. [{Project(\{r.IdRicetta, r.Nome, r.IdCreatrice\})}
  32. [{TableScan(Ricette r)}]
  33. ]
  34. ]
  35. ]
  36. ]
  37. \end{forest}
  38. \end{center}
  39. \paragraph{Piano di accesso fisico della query a con due indici}
  40. \begin{center}
  41. \begin{forest}, baseline, qtree
  42. [{Project(\{r.IdRicetta , r.Nome\})}
  43. [{IndexNestedLoop(p.IdPersona = r.IdCreatrice)}
  44. [{IndexFilter(Persone p,\\ IndPN, p.Nome = 'Giovanni')}]
  45. [{IndexFilter(Ricette r,\\IndRC, r.IdCreatrice = p.IdPersona)}]
  46. ]
  47. ]
  48. \end{forest}
  49. \end{center}
  50. Indici necessari: \texttt{IndPN} (indice della tabella Persone sull’attributo
  51. Nome) e \texttt{IndRC} (indice della tabella Ricette sull'attributo Creatrice).
  52. \clearpage
  53. \subsection{Query b}
  54. \paragraph{Piano di accesso logico della query b}
  55. \begin{center}
  56. \begin{forest}, baseline, qtree
  57. [{$\tau$[-DiversiFornitori]}
  58. [{$\pi^{b}$ fa.IdBirrificio, COUNT(DISTINCT fa.IdFornitore) DiversiFornitori}
  59. [{$\sigma$ COUNT(DISTINCT fa.IdFornitore) $>=$ 3}
  60. [\{fa.IdBirrificio\} {$\gamma$ \{COUNT(DISTINCT fa.IdFornitore)\}}
  61. [{$\sigma$ fa.Data $>=$ '2020-01-01'}
  62. [Fatture fa]
  63. ]
  64. ]
  65. ]
  66. ]
  67. ]
  68. \end{forest}
  69. \end{center}
  70. Non c'è in questo caso differenza tra $\pi^{b}$ e $\pi$: non ci possono essere
  71. duplicati, in quanto la GROUP BY raggruppa per IdBirrificio.
  72. \paragraph{Piano di accesso fisico della query b senza indici}
  73. \begin{center}
  74. \begin{forest}, baseline, qtree
  75. [{Sort[-DiversiFornitori]}
  76. [{Project(\{fa.IdBirrificio, COUNT(DISTINCT fa.IdFornitore) DiversiFornitori\})}
  77. [{Filter(COUNT(DISTINCT fa.IdFornitore) $>=$ 3)}
  78. [{GroupBy(\{fa.IdBirrificio\}, \{COUNT(DISTINCT fa.IdFornitore)\})}
  79. [{Sort([fa.IdBirrificio])}
  80. [{Filter(fa.Data $>=$ '2020-01-01')}
  81. [{TableScan(Fatture fa)}]
  82. ]
  83. ]
  84. ]
  85. ]
  86. ]
  87. ]
  88. \end{forest}
  89. \end{center}
  90. Il sort sull'attributo dimensione di analisi prima della GroupBy è necessario,
  91. in quanto non è garantito che i record della tabella Fatture siano raggruppati
  92. per IdBirrificio.
  93. Lo sarebbero se l'organizzazione primaria della tabella fosse sequenziale
  94. proprio su questo attributo, il che è estremamente poco probabile.
  95. \clearpage
  96. \paragraph{Piano di accesso fisico della query b con un indice}
  97. \begin{center}
  98. \begin{forest}, baseline, qtree
  99. [{Sort[-DiversiFornitori]}
  100. [{Project(\{fa.IdBirrificio, COUNT(DISTINCT fa.IdFornitore) DiversiFornitori\})}
  101. [{Filter(COUNT(DISTINCT fa.IdFornitore) $>=$ 3)}
  102. [{GroupBy(\{fa.IdBirrificio\}, \{COUNT(DISTINCT fa.IdFornitore)\})}
  103. [{Sort([fa.IdBirrificio])}
  104. [{IndexFilter(Fatture fa, IndFD, fa.Data $>=$ '2020-01-01')}]
  105. ]
  106. ]
  107. ]
  108. ]
  109. ]
  110. \end{forest}
  111. \end{center}
  112. Indice necessario: \texttt{IndFD} (indice della tabella Fatture sull’attributo
  113. Data).
  114. Il sort sull'attributo IdBirrificio prima della GroupBy è necessario, in quanto
  115. i record in input sono ordinati per data, il che non ci garantisce che siano
  116. raggruppati per IdBirrificio (che è dimensione di analisi).
  117. \subsection{Query c}
  118. \paragraph{Piano di accesso logico della query c}
  119. \begin{center}
  120. \begin{forest}, baseline, qtree
  121. [{$\pi^{b}$ fo.RagioneSociale, SUM(fa.Importo) ImportoTotale, AVG(fa.Importo) ImportoMedio}
  122. [$\sigma$ SUM(fa.Importo) $>$ 10
  123. [{\{fo.IdFornitore, fo.RagioneSociale\} $\gamma$ \{SUM(fa.Importo), AVG(fa.Importo)\}}
  124. [{$\bowtie$ fa.IdFornitore = fo.IdFornitore}
  125. [{Fornitori fo}]
  126. [{$\bowtie$ fa.IdBirrificio = b.IdBirrificio}
  127. [{$\sigma$ b.Nome = 'Pirati Rossi'}
  128. [{Birrifici b}]
  129. ]
  130. [{Fatture fa}]
  131. ]
  132. ]
  133. ]
  134. ]
  135. ]
  136. \end{forest}
  137. \end{center}
  138. In questo caso non ci dovrebbe essere differenza tra $\pi^{b}$ e $\pi$: non ci
  139. devono essere due fornitori con la stessa ragione sociale (la ragione sociale
  140. è chiave naturale); è comunque possibile un errore di inserimento se non ho
  141. impostato un vincolo di unicità anche su questo attributo, che non ho scelto
  142. come chiave primaria della tabella: ecco perché ho raggruppato anche per
  143. IdFornitore e non solo per RagioneSociale.
  144. Ho scelto l'ordine di giunzione in modo da avere la restrizione il più distale
  145. possibile.
  146. \clearpage
  147. \paragraph{Piano di accesso fisico della query c senza indici}
  148. \begin{center}
  149. \begin{forest}, baseline, qtree
  150. [{Project(\{fo.RagioneSociale,\\SUM(fa.Importo) ImportoTotale, AVG(fa.Importo) ImportoMedio\})}
  151. [{Filter(SUM(fa.Importo) $>$ 10)}
  152. [{GroupBy(\{fo.IdFornitore,fo.RagioneSociale\}, \{SUM(fa.Importo), AVG(fa.Importo)\})}
  153. [{MergeSort(fa.IdFornitore = fo.IdFornitore)}
  154. [{Sort([fo.IdFornitore])}
  155. [{Project(\{fo.IdFornitore,\\fo.RagioneSociale\})}
  156. [{Fornitori fo}]
  157. ]
  158. ]
  159. [{Sort([fa.IdFornitore])}
  160. [{Project(\{fa.IdFornitore, fa.Importo\})}
  161. [{MergeSort(fa.IdBirrificio = b.IdBirrificio)}
  162. [{Sort([b.IdBirrificio])}
  163. [{Project(\{b.IdBirrificio\})}
  164. [{Filter(b.Nome = 'Pirati Rossi')}
  165. [{TableScan(Birrifici b)}]
  166. ]
  167. ]
  168. ]
  169. [{Sort([fa.IdBirrificio])}
  170. [{Project(\{fa.IdBirrificio,\\fa.IdFornitore fa.Importo\})}
  171. [{Fatture fa}]
  172. ]
  173. ]
  174. ]
  175. ]
  176. ]
  177. ]
  178. ]
  179. ]
  180. ]
  181. \end{forest}
  182. \end{center}
  183. Non è necessario ordinare per \texttt{[fo.IdFornitore, fo.RagioneSociale]} prima
  184. della GroupBy: per costruzione, l'ordine dell'operatore esterno della SortMerge
  185. viene mantenuto nell'output, e questo ordine è sull'attributo fo.IdFornitore,
  186. che a sua volta determina funzionalmente l'altra dimensione di analisi, fo.RagioneSociale.
  187. Pertanto, è garantito che l'input della GroupBy sarà già raggruppato per gli
  188. attributi che sono dimensione di analisi e non occorre un ordinamento
  189. preventivo.
  190. \clearpage
  191. \paragraph{Piano di accesso fisico della query c con tre indici}
  192. \begin{center}
  193. \begin{forest}, baseline, qtree
  194. [{Project(\{fo.RagioneSociale,\\SUM(fa.Importo) ImportoTotale, AVG(fa.Importo) ImportoMedio\})}
  195. [{Filter(SUM(fa.Importo) $>$ 10)}
  196. [{GroupBy(\{fo.IdFornitore, fo.RagioneSociale\},\\\{SUM(fa.Importo), AVG(fa.Importo)\})}
  197. [{Sorted([fo.IdFornitore])}
  198. [{Project(\{fo.IdFornitore, fo.RagioneSociale, fa.Importo\})}
  199. [{IndexNestedLoop(fa.IdFornitore = fo.IdFornitore)}
  200. [{IndexNestedLoop\\(fa.IdBirrificio = b.IdBirrificio)}
  201. [{IndexFilter(Birrifici b, IndBN,\\b.Nome = 'Pirati Rossi')}]
  202. [{IndexFilter(Fatture fa, IndFaIdB,\\fa.IdBirrificio = b.IdBirrificio)}]
  203. ]
  204. [{IndexFilter(Fornitori fo, IndFoIdF,\\fo.IdFornitore = fa.IdFornitore)}]
  205. ]
  206. ]
  207. ]
  208. ]
  209. ]
  210. ]
  211. \end{forest}
  212. \end{center}
  213. Indici necessari: \texttt{IndBN} (indice della tabella Birrifici sull’attributo
  214. Nome), \texttt{IndFaIdB} (indice della tabella Fatture sull'attributo
  215. IdBirrificio) e \texttt{IndFoIdF} (indice della tabella Fornitori sull'attributo
  216. IdFornitore).
  217. Occorre ordinare per IdFornitore prima della \texttt{GroupBy}, in quanto
  218. l'output della IndexNestedLoop è ordinato come l'operatore esterno, ovvero
  219. per nome del birrificio.
  220. Potrei spostare l'ordinamento tra le due giunzioni con IndexNestedLoop, tanto
  221. ogni fattura ha un fornitore e l'output non andrà a decrecere dopo la seconda
  222. giunzione (anzi, si arricchirà di campi).
  223. Il sort andrebbe fatto con il minor numero possibile di dati, dato l'alto costo
  224. dell'algoritmo, eliminando i campi superflui con una project prima.
  225. Il vantaggio dell'IndexNestedLoop sul SortMerge si ha solo se la condizione è
  226. sufficientemente restrittiva da essere soddisfatta da una piccola minoranza
  227. di record.
  228. In questo caso, la restrizione sul nome del birrificio dovrebbe essere
  229. abbastanza restrittiva (se ci sono abbastanza birrifici, il numero di
  230. birrifici con il nome `Pirati Rossi' sarà trascurabile rispetto al totale) ed
  231. è ragionevole che le fatture che riguardano quel birrificio siano una esigua
  232. minoranza rispetto al totale delle fatture.
  233. Se così non fosse, pur avendo i tre indici a disposizione, converrebbe
  234. utilizzare comunque il SortMerge.