Principe du pipeline de réécriture

Readyset ne réexécute pas les requêtes à la volée. Lorsqu’une CREATE CACHE est déclenchée, la requête SQL est traduite en un directed acyclic graph (DAG) d’opérateurs de streaming (joins, filtres, agrégations, projections). Chaque opérateur reçoit les changements d’entrée et émet les changements de sortie, ce qui permet de maintenir incrémentalement le résultat pré‑calculé dès qu’une ligne est insérée, mise à jour ou supprimée dans la base source. Ainsi, les lectures se limitent à des recherches dans une vue matérialisée plutôt qu’à une exécution complète du plan.

Contraintes imposées par le moteur de flux de données

Le compilateur de Readyset impose plusieurs restrictions syntaxiques. Les joins binaires doivent reposer exclusivement sur des prédicats d’égalité de colonnes (a.id = b.id) afin de pouvoir conserver un état de jointure hash‑based. Les prédicats de plage, les clés d’expression ou les conditions ON multi‑tables ne sont pas supportés. Les sous‑requêtes corrélées, qui dans les moteurs classiques s’exécutent par boucle imbriquée, doivent être réécrites en joins équivalents, car le graphe ne possède pas de notion « par ligne externe ». Les types de jointure acceptés sont INNER JOIN, LEFT OUTER JOIN et CROSS JOIN ; RIGHT JOIN et FULL OUTER JOIN sont exclus en raison de la difficulté à suivre l’absence de correspondance des deux côtés dans un flux continu. Enfin, les agrégations requièrent que chaque GROUP BY utilise des références de colonnes explicites et que la requête projette au moins une expression dérivée d’agrégation.

Étapes du pipeline : normalisation, réécritures profondes, nettoyage

Le processus de réécriture s’articule en trois blocs successifs, chacun préservant la sémantique d’origine.

Bloc A – Normalisation : désugarisation de la syntaxe, résolution de schémas, expansion du SELECT * en liste explicite, qualification des colonnes (id → t.id) et conversion des clauses USING en ON. Cette étape garantit que les passes suivantes opèrent sur une forme canonique.

SELECT * FROM users;

devient

SELECT users.id, users.name, users.email FROM users;

Bloc B – Réécritures profondes : décorrélation des sous‑requêtes, aplatissement des tables dérivées et transformation d’opérations IN (SELECT …) en joins. L’objectif est de supprimer toute construction qui ne peut être représentée par un opérateur de flux.

Bloc C – Nettoyage : suppression des clauses redondantes (ex. ORDER BY ou LIMIT lorsqu’une seule ligne est garantie), paramétrisation des littéraux et élimination des artefacts introduits par le bloc B.

Implications de performance et limites

En optimisant une fois lors de la création du cache, Readyset élimine la latence proportionnelle à la complexité de la requête et à la taille des données. Cependant, la nécessité de respecter les contraintes du graphe implique que certaines requêtes valides sur PostgreSQL ou MySQL ne sont pas directement compilables, ou bien subissent une réécriture qui augmente la charge de stockage (ex. matérialisation d’une table dérivée non inlinée). De plus, l’absence de support pour les joins à droite ou complets limite les cas d’usage où la non‑correspondance doit être détectée. Les développeurs doivent donc anticiper ces restrictions lors de la conception de leurs caches, sinon le pipeline pourra générer une version moins efficace ou refuser la compilation.