Accélérer vos requêtes avec les vues matérialisées dans Apache Hive
31 mai 2018
Ne ratez pas nos articles sur l'open source, le big data et les systèmes distribués, fréquence faible d’un email tous les deux mois.
Jesus Camacho Rodriguez a organisé une présentation “Accelerating query processing with materialized views in Apache Hive” sur une nouvelle fonctionnalité à venir dans Apache Hive 3.0 : les vues matérialisées.
Cet article va décrire le principe général de cette fonctionnalité, donner quelques exemples et les améliorations prévues dans la roadmap du projet.
Ni une vue, ni une table : voici la vue matérialisée
D’après Wikipédia, une vue SQL est la synthèse d’une requête sur une base des données. En tant qu’utilisateur d’une base de données, vous accédez à vos données en pratiquant souvent les mêmes jointures, filtres ou agrégations. À l’aide d’une vue, il n’est pas nécessaire de répéter les mêmes requêtes complexes à chaque fois. On peut ainsi simplifier l’accès aux données tout en donnant plus de sens à l’utilisateur.
Par exemple un utilisateur a besoin d’un jeu de données d’un commerce. Pour accéder à la liste des marques préférées des clients, on va avoir besoin de faire une jointure sur les tables Clients, Commandes et Produit. On peut facilement cacher la complexité de ce schéma à l’utilisateur avec une seule table et gérer son accès avec ses propres ACLs.
Cependant des vues virtuelles sont composées de requêtes lentes et gourmandes. On pourrait à la place stocker le résultat de notre requête dans une autre table régulièrement, mais cela implique de modifier les modèles d’accès et il n’est pas simple de s’assurer que les données restent à jour.
Nous pouvons identifier quatre types d’optimisations :
- Modifier physiquement la répartition des données (Tri, distribution…) ;
- Filtrage et partitionnage ;
- Dénormalisation ;
- Pre agrégation.
Le but des vues matérialisées (MV) est d’augmenter les performances des requêtes en ne nécessitant aucune maintenance.
Les principales fonctionnalités sont :
- Stocker le résultat d’une requête dans une table (Le stockage peut s’effectuer dans Hive ou dans Druid)
- La définition de la vue est utilisée pour réécrire la requête et ne demande aucun changement dans les modèles d’accès
- La fraîcheur des données est assurée par le système
- Une insertion dans la table est très efficace puis qu’elle ne demande pas de reconstruire la vue
Exemples
Voyons quelques exemples pour illustrer les capacités de réécriture.
Dénormalisation et filtrage
La dénormalisation consiste à grouper plusieurs tables dans une table plus grande. Les opérations JOIN
très lourdes ne sont ainsi plus nécessaires.
Nous étudierons ici deux tables contenant des employés avec leur départements respectifs dans l’entreprise.
Dans cet exemple nous allons dénormaliser ces tables et filtrer nos entrées selon la date d’embauche de nos employés :
empId | empName | deptID | empSalary | empHireDate |
---|---|---|---|---|
0 | Frodo | 10 | 20000 | 2018-03-03 |
1 | Sam | 10 | 22300 | 2016-11-11 |
2 | Gimli | 20 | 42300 | 2016-02-13 |
3 | Galadriel | 30 | 50000 | 2015-05-28 |
4 | Legolas | 30 | 72000 | 2015-05-01 |
deptId | deptName |
---|---|
10 | Accounting |
20 | Workers |
30 | HR |
Notre requête pourrait ressembler à quelque chose comme ça pour lister les employés des Ressources Humaines recrutés au premier semestre 2016 :
SELECT employees.empId, employees.empName
FROM employees JOIN departments
ON (employees.deptId = departments.deptId)
AND departments.deptName = 'HR'
AND employees.empHireDate >= '2016-01-01'
AND employees.empHireDate <= '2016-07-01';
Et voilà la vue matérialisée créée précédemment, contenant les employés et leur départements, filtrés sur l’année 2016.
CREATE MATERIALIZED VIEW mv AS
SELECT
employees.empId as empId,
employees.empName as empName,
departments.deptId as deptId,
departments.deptName as deptName
employees.empHireDate as empHireDate
from employees, departments
WHERE employees.deptId = departments.deptId
AND employees.empHireDate >= '2016-01-01'
AND employees.empHireDate <= '2016-12-31';
Notre requête une fois réécrite ressemble désormais à ceci, plus besoin de JOIN
:
SELECT empId, empName
from mv
AND deptName = 'HR'
AND empHireDate <= '2016-07-01'
Regroupement
Dans cet exemple nous stockons l’activité des utilisateurs sur un dépôt GIT. Chaque entrée contient le nombre de lignes ajoutées et supprimées d’un commit.
commitId | commitDate | commitAuthor | commitLinesAdded | commitLinesRemoved |
---|---|---|---|---|
0b42f0b | 2018-01-02 18:04:33 | Linus | 123 | 3 |
d346b3d | 2018-01-03 17:33:46 | Linus | 2 | 234 |
7151de5 | 2018-01-03 18:24:21 | Richard | 13 | 11 |
... | ... | ... | ... | ... |
À l’aide d’une vue matérialisée, on peut regrouper les commits par jour et uniquement stocker l’agrégation des lignes. C’est un cas d’utilisation très pertinent dans le cadre d’un stockage sur Druid.
CREATE MATERIALIZED VIEW mv_commits_by_day
STORED AS 'org.apache.hadoop.hive.druid.DruidStorageHandler'
AS
SELECT
floor(time to day),
commitAuthor as author,
sum(commitLinesAdded) as linesAdded,
sum(commitLinesRemoved) as linesRemoved
FROM commits
GROUP BY floor(time to day), author
Nos requêtes peuvent maintenant être très optimisées. Avant la réécriture :
SELECT
floor(time to month),
sum(commitLinesAdded)
FROM commits
GROUP BY floor(time to month)
Après la réécriture, la requête est bien plus légère grâce au groupement des lignes :
SELECT
floor(time to month),
sum(linesAdded)
FROM mv_commits_by_day
GROUP BY floor(time to month)
Activer la réécriture de requêtes
La réécriture de requêtes utilisant les vues matérialisées s’active avec la propriété suivante : SET hive.materializedview.rewriting=true;
.
À l’échelle d’une vue, on peut activer ou désactiver la réécriture : ALTER MATERIALIZED VIEW mv ENABLE|DISABLE REWRITE
.
La réécriture de requêtes est activée par défaut pour toutes les vues matérialisées.
Reconstruire une vue matérialisée
Une fois la vue créée, elle va présenter une image de ce qui est présent dans la table d’origine à un instant t.
Mais une fois la table mise à jour, la vue doit être reconstruite manuellement pour rester pertinente.
ALTER MATERIALIZED VIEW mv REBUILD;
Le moteur va toujours essayer une reconstruction incrémentale plutôt qu’une reconstruction complète. Actuellement une reconstruction incrémentale n’est possible que dans le cas d’une insertion dans la table.
Si un DELETE
ou un UPDATE
a été réalisé, la vue doit être entièrement reconstruite.
Données obsolètes
Une vue matérialisée est considérée comme obsolète dès que des modifications dans la table originale ont eu lieu.
Le système est capable de suivre le statut de ses vues. L’optimiseur va donc utiliser une combinaison des données obsolètes de la vue et des données fraîches de la table.
Le comportement par défaut est d’ignorer les données obsolètes, il est possible de changer ceci avec le paramètre hive.materializedview.rewriting.time.window
. Ce paramètre est un intervalle pendant lequel les vues obsolètes peuvent quand même être utilisés pour la réécriture de requêtes.
Roadmap
Les développements sont toujours en cours et plusieurs améliorations sont prévues :
- Amélioration de l’algorithme de réécriture de requête dans Apache Calcite ;
- Gestion de la distribution des données dans la vue (
SORT BY
,CLUSTER BY
,DISTRIBUTE BY
) ; - Support des
UPDATE
etDELETE
dans la reconstruction incrémentale des vues.
Conclusion
Cette nouvelle fonctionnalité de Hive est très prometteuse. On peut facilement l’intégrer à un grand nombre de cas d’utilisation grâce aux faibles impacts qu’elle engendre.
La nécessité d’une reconstruction complète après chaque mise à jour est encore un point très limitant. Cette amélioration est prévue dans la roadmap.
Les vues matéralisées devraient être disponible dans Hive 3.0.
Liens
JIRA sur la fonctionnalité dans Apache Calcite
Accelerating query processing with materialized views in Apache Hive