La réécriture de requête permet à AnalyticDB for MySQL de rediriger automatiquement les requêtes vers des vues matérialisées, sans aucune modification de votre code SQL. Lorsqu'une requête correspond à une vue matérialisée, le moteur lit les résultats précalculés au lieu d'analyser les tables de base, ce qui peut réduire considérablement la latence des requêtes.
Prérequis
-
Un cluster AnalyticDB for MySQL exécute la version mineure 3.1.4.0 ou ultérieure.
RemarquePour vérifier la version mineure d'un cluster Data Lakehouse Edition, exécutez
SELECT adb_version();. Pour mettre à niveau la version mineure, contactez le support technique.Pour afficher et mettre à niveau la version mineure d'un cluster Data Warehouse Edition, consultez la rubrique Mise à niveau de la version mineure.
-
Pour utiliser les vues matérialisées, les autorisations suivantes sont requises :
Autorisation CREATE sur la base de données où réside la vue matérialisée.
Autorisation SELECT sur les colonnes concernées, ou sur l'intégralité des tables, de toutes les tables de base de la vue matérialisée.
-
Pour créer une vue matérialisée qui est actualisée automatiquement, les deux autorisations suivantes sont également requises :
Autorisation de se connecter à AnalyticDB for MySQL depuis n'importe quelle adresse IP (c'est-à-dire
'%').Autorisation INSERT sur la vue matérialisée ou sur toutes les tables de la base de données où réside la vue matérialisée. Sinon, les données de la vue matérialisée ne peuvent pas être actualisées.
Fonctionnement
AnalyticDB for MySQL compare chaque requête entrante à toutes les vues matérialisées pour lesquelles la réécriture de requête est activée. Si une correspondance est trouvée, le moteur réécrit la requête pour lire les données depuis la vue matérialisée plutôt que depuis les tables de base. Deux stratégies de mise en correspondance sont utilisées, appliquées dans l'ordre suivant :
Réécriture par correspondance exacte — lorsque la structure de la requête est identique à la définition de la vue matérialisée. Il s'agit de la stratégie la plus simple, soumise à moins de restrictions.
Réécriture de requête avancée — lorsque les structures diffèrent. Le moteur applique des règles de réécriture (FILTER, JOIN, AGGREGATION, AGGREGATION ROLLUP, SUBQUERIES, QUERY PARTIAL, UNION) pour déterminer si la vue matérialisée contient suffisamment de données pour répondre à la requête ou à une partie de celle-ci. Différentes sous-requêtes dans la même instruction peuvent correspondre à différentes vues matérialisées.
Toutes les réécritures de requête s'effectuent au niveau STALE_TOLERATED : le moteur réécrit une requête même si la vue matérialisée contient des données obsolètes qui n'ont pas été synchronisées depuis les tables de base. Cela maximise la couverture de la réécriture, mais signifie que les résultats peuvent ne pas refléter les dernières insertions ou mises à jour. Actualisez vos vues matérialisées avant d'exécuter des requêtes sensibles à la latence. Pour plus de détails, consultez la rubrique Configuration de l'actualisation complète des vues matérialisées.
Activation de la réécriture de requête
Activez la réécriture de requête de l'une des deux manières suivantes :
Lors de la création, incluez la clause
ENABLE QUERY REWRITEdans votre instructionCREATE MATERIALIZED VIEW. Consultez la section Création d'une vue matérialisée — Paramètres.-
Après la création, exécutez :
ALTER MATERIALIZED VIEW <mv_name> ENABLE QUERY REWRITE;Consultez la rubrique Gestion des vues matérialisées.
Désactivation de la réécriture de requête
Désactivez la réécriture de requête de l'une des deux manières suivantes :
-
Pour une vue matérialisée spécifique :
ALTER MATERIALIZED VIEW <mv_name> DISABLE QUERY REWRITE; -
Pour une requête spécifique, ajoutez un indice avant l'instruction
SELECT:/*+MV_QUERY_REWRITE_ENABLED=false*/ SELECT ...
Vérification de l'activation de la réécriture de requête
Après avoir activé la réécriture de requête, utilisez EXPLAIN pour confirmer que le moteur lit les données depuis la vue matérialisée.
Exemple
-
Créez une vue matérialisée avec la réécriture de requête activée.
CREATE MATERIALIZED VIEW adb_mv REFRESH START WITH now() + interval 1 day ENABLE QUERY REWRITE AS SELECT course_id, course_name, max(course_grade) AS max_grade FROM tb_courses; -
Après avoir activé la réécriture de requête, exécutez
EXPLAINsur la requête.EXPLAIN SELECT course_id, course_name, max(course_grade) AS max_grade FROM tb_courses; -
Vérifiez le plan d'exécution. Lorsque la réécriture de requête est active, la ligne
TableScanaffiche le nom de la vue matérialisée (adb_mv), et non celui de la table de base (tb_courses).+---------------+ | Plan Summary | +---------------+ 1- Output[ Query plan ] {Est rowCount: 1.0} 2 -> Exchange[GATHER] {Est rowCount: 1.0} 3 - TableScan {table: adb_mv, Est rowCount: 1.0}Si le plan affiche toujours
TableScan {table: tb_courses, ...}, la réécriture de requête ne s'est pas activée. Consultez la section Dépannage.
Portée de la réécriture
Les exemples suivants illustrent chaque règle de réécriture prise en charge par la méthode de réécriture de requête avancée. Tous les exemples utilisent les quatre mêmes tables :
CREATE TABLE part (
partkey INTEGER NOT NULL,
name VARCHAR(55) NOT NULL,
type VARCHAR(25) NOT NULL
);
CREATE TABLE lineitem (
orderkey BIGINT,
partkey BIGINT NOT NULL,
suppkey BIGINT NOT NULL,
extendedprice DOUBLE NOT NULL,
discount DOUBLE NOT NULL,
returnflag CHAR(1) NOT NULL,
linestatus CHAR(1) NOT NULL,
shipdate DATE NOT NULL,
shipmode VARCHAR(25) NOT NULL,
commitdate DATE NOT NULL,
receiptdate DATE NOT NULL
);
CREATE TABLE orders (
orderkey BIGINT PRIMARY KEY,
custkey BIGINT NOT NULL,
orderstatus VARCHAR(1) NOT NULL,
totalprice DOUBLE NOT NULL,
orderdate DATE NOT NULL
);
CREATE TABLE partsupp (
partkey INTEGER NOT NULL PRIMARY KEY,
suppkey INTEGER NOT NULL,
availqty INTEGER NOT NULL,
supplycost DECIMAL(15,2) NOT NULL
);
Réécriture par correspondance exacte
Lorsque la structure de la requête est identique à la définition de la vue matérialisée, le moteur réécrit directement la requête.
Requête
SELECT
l.returnflag,
l.linestatus,
SUM(l.extendedprice * (1 - l.discount)),
COUNT(*) AS count_order
FROM lineitem AS l
GROUP BY l.returnflag, l.linestatus;
Vue matérialisée
CREATE MATERIALIZED VIEW mv0
REFRESH NEXT now() + interval 1 day
ENABLE QUERY REWRITE
AS
SELECT
l.returnflag,
l.linestatus,
SUM(l.extendedprice * (1 - l.discount)) AS sum_disc_price,
COUNT(*) AS count_order
FROM lineitem AS l
GROUP BY l.returnflag, l.linestatus;
Requête réécrite
SELECT returnflag, linestatus, sum_disc_price, count_order
FROM mv0;
Réécriture de requête avancée
FILTER
Lorsque le prédicat de la requête est plus restrictif que le prédicat de la vue matérialisée, le moteur ajoute une clause WHERE à l'analyse de la vue matérialisée pour appliquer le filtre manquant. Si une expression présente dans la requête n'existe pas dans la vue matérialisée, le moteur tente également de calculer l'expression à partir de la vue.
Requête
SELECT
l.shipmode,
l.extendedprice * (1 - l.discount) AS disc_price
FROM orders AS o, lineitem AS l
WHERE o.orderkey = l.orderkey
AND l.shipmode IN ('REG AIR', 'TRUCK')
AND l.commitdate < l.receiptdate
AND l.shipdate < l.commitdate;
Vue matérialisée
CREATE MATERIALIZED VIEW mv1
REFRESH NEXT now() + interval 1 day
ENABLE QUERY REWRITE
AS
SELECT
l.shipmode,
l.extendedprice,
l.discount
FROM orders AS o, lineitem AS l
WHERE o.orderkey = l.orderkey
AND l.commitdate < l.receiptdate
AND l.shipdate < l.commitdate;
Requête réécrite
SELECT
shipmode,
extendedprice * (1 - discount) AS disc_price,
discount
FROM mv1
WHERE shipmode IN ('REG AIR', 'TRUCK');
JOIN
Lorsque la requête et la vue matérialisée présentent des relations de jointure différentes, le moteur déduit la jointure requise à partir de la vue matérialisée. Par exemple, une vue matérialisée avec une jointure externe peut satisfaire une requête nécessitant une jointure interne en filtrant les lignes nulles.
Types de jointure pris en charge : jointure interne, jointure externe, jointure gauche et jointure droite.
Requête
SELECT
p.type,
p.partkey,
ps.suppkey
FROM part AS p, partsupp AS ps
WHERE p.partkey = ps.partkey
AND p.type NOT LIKE 'MEDIUM POLISHED%';
Vue matérialisée
CREATE MATERIALIZED VIEW mv2
REFRESH NEXT now() + INTERVAL 1 day
ENABLE QUERY REWRITE
AS
SELECT
p.type,
p.partkey,
ps.suppkey
FROM partsupp AS ps
INNER JOIN part AS p ON p.partkey = ps.partkey
WHERE p.type NOT LIKE 'MEDIUM POLISHED%';
Requête réécrite
SELECT type, partkey, suppkey
FROM mv2;
AGGREGATION
Lorsque la requête ou la vue matérialisée utilise des clauses GROUP BY ou des fonctions d'agrégation différentes, le moteur construit la même fonction d'agrégation à partir de la vue matérialisée en utilisant la règle AGGREGATION.
Requête
SELECT
l.returnflag,
l.linestatus,
SUM(l.extendedprice * (1 - l.discount)) AS sum_disc_price
FROM lineitem AS l
GROUP BY l.returnflag, l.linestatus;
Vue matérialisée
CREATE MATERIALIZED VIEW mv3
REFRESH NEXT now() + INTERVAL 1 day
ENABLE QUERY REWRITE
AS
SELECT
l.returnflag,
l.linestatus,
SUM(l.extendedprice * (1 - l.discount)) AS sum_disc_price,
COUNT(*) AS count_order
FROM lineitem AS l
GROUP BY l.returnflag, l.linestatus;
Requête réécrite
SELECT returnflag, linestatus, sum_disc_price, count_order
FROM mv3;
AGGREGATION ROLLUP
Lorsque la requête regroupe les données selon un sous-ensemble des champs GROUP BY de la vue matérialisée, le moteur effectue un rollup des agrégats précalculés.
Requête
SELECT
l.returnflag,
SUM(l.extendedprice * (1 - l.discount)) AS sum_disc_price,
COUNT(*) AS count_order
FROM lineitem AS l
WHERE l.returnflag = 'R'
GROUP BY l.returnflag;
Vue matérialisée
CREATE MATERIALIZED VIEW mv4
REFRESH NEXT now() + INTERVAL 1 day
ENABLE QUERY REWRITE
AS
SELECT
l.returnflag,
l.linestatus,
SUM(l.extendedprice * (1 - l.discount)) AS sum_disc_price,
COUNT(*) AS count_order
FROM lineitem AS l
GROUP BY l.returnflag, l.linestatus;
Requête réécrite
SELECT
returnflag,
linestatus,
sum_disc_price,
count_order
FROM mv4
WHERE returnflag = 'R'
GROUP BY returnflag;
SUBQUERIES
Lorsque la requête utilise une sous-requête à la place d'une table de base, le moteur vérifie si la vue matérialisée couvre la table entière et pousse le filtre de la sous-requête dans l'analyse réécrite.
Requête
SELECT
p.type,
p.partkey,
ps.suppkey
FROM part AS p,
(SELECT * FROM partsupp WHERE suppkey > 10) ps
WHERE p.partkey = ps.partkey;
Vue matérialisée
CREATE MATERIALIZED VIEW mv5
REFRESH NEXT now() + INTERVAL 1 day
ENABLE QUERY REWRITE
AS
SELECT
p.type,
p.partkey,
ps.suppkey
FROM part AS p, partsupp AS ps
WHERE p.partkey = ps.partkey;
Requête réécrite
SELECT type, partkey, suppkey
FROM mv5
WHERE suppkey > 10;
QUERY PARTIAL
Lorsque la requête fait référence à une table non couverte par la vue matérialisée, le moteur joint la vue matérialisée à la table manquante.
Requête
SELECT
p.type,
p.partkey,
ps.suppkey
FROM part AS p, partsupp AS ps
WHERE p.partkey = ps.partkey
AND p.type NOT LIKE 'MEDIUM POLISHED%';
Vue matérialisée
CREATE MATERIALIZED VIEW mv6
REFRESH NEXT now() + INTERVAL 1 day
ENABLE QUERY REWRITE
AS
SELECT
p.type,
p.partkey
FROM part AS p
WHERE p.type NOT LIKE 'MEDIUM POLISHED%';
Requête réécrite
SELECT
mv6.type,
mv6.partkey,
ps.suppkey
FROM mv6, partsupp AS ps
WHERE mv6.partkey = ps.partkey;
UNION
Lorsque la vue matérialisée ne couvre qu'une partie de la plage de dates ou de valeurs de la requête, le moteur récupère la partie couverte depuis la vue matérialisée et extrait les lignes restantes directement depuis la table de base, puis combine les résultats avec UNION ALL.
Requête
SELECT
l.linestatus,
COUNT(*) AS count_order
FROM lineitem AS l
WHERE l.shipdate >= DATE '1998-01-01'
GROUP BY l.linestatus;
Vue matérialisée (couvre uniquement shipdate >= 2000-01-01)
CREATE MATERIALIZED VIEW mv7
REFRESH NEXT now() + interval 1 day
ENABLE QUERY REWRITE
AS
SELECT
l.linestatus,
COUNT(*) AS count_order
FROM lineitem AS l
WHERE l.shipdate >= DATE '2000-01-01'
GROUP BY l.linestatus;
Requête réécrite
SELECT linestatus, count_order
FROM (
SELECT linestatus, count_order
FROM mv7
UNION ALL
SELECT
l.linestatus,
COUNT(*) AS count_order
FROM lineitem AS l
WHERE l.shipdate >= DATE '1998-01-01' AND l.shipdate < DATE '1998-01-01'
GROUP BY l.linestatus
)
GROUP BY linestatus;
Limitations
Réécriture par correspondance exacte
La méthode de réécriture par correspondance exacte ne s'active pas si la vue matérialisée contient :
Des fonctions non déterministes :
NOW,CURRENT_TIMESTAMP,RANDOMDes fonctions définies par l'utilisateur (UDF)
Réécriture de requête avancée
La méthode de réécriture de requête avancée ne s'active pas si la vue matérialisée contient l'un des éléments suivants :
Clause
ORDER BY,LIMITouOFFSETClause
UNIONouUNION ALLGROUPING SETS,CUBEouROLLUPdans une clauseGROUP BYFonctions de fenêtrage
FULL OUTER JOINTables système
Sous-requêtes corrélées
Fonctions non déterministes :
NOW,CURRENT_TIMESTAMP,RANDOMUDF
Clause
HAVINGSELF JOIN
Types d'instructions pour lesquels la réécriture de requête ne s'active jamais
La réécriture de requête ne s'applique pas aux requêtes intégrées dans les types d'instructions suivants, quelle que soit la définition de la vue matérialisée :
CREATE TABLE AS SELECTINSERT INTO SELECTINSERT OVERWRITE SELECTREPLACE INTO SELECTDELETEouUPDATE
Requêtes sur table unique sans filtres ni agrégats
La réécriture de requête ne s'active pas pour les requêtes sur table unique qui ne comportent ni conditions de filtre ni fonctions d'agrégation.
Dépannage
La réécriture de requête ne s'active pas après la création d'une vue matérialisée.
Commencez par examiner les causes les plus fréquentes :
La réécriture de requête n'est pas activée sur la vue matérialisée. Exécutez
ALTER MATERIALIZED VIEW <mv_name> ENABLE QUERY REWRITE;et réessayez.La vue matérialisée atteint une limite. Consultez la section Limitations et vérifiez si la définition de votre vue matérialisée inclut une clause ou une fonction non prise en charge.
-
Autorisation SELECT manquante sur la vue matérialisée. Accordez l'autorisation requise au compte exécutant la requête :
GRANT SELECT ON <database>.<mv_name> TO '<account>';Pour plus de détails, consultez la section Autorisations requises de la rubrique Interrogation des données d'une vue matérialisée.