Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.
Requêtes à partition unique dans Aurora PostgreSQL Limitless Database
Une requête à partition unique est une requête qui peut être exécutée directement sur une partition, tout en conservant les propriétés ACID
Cette optimisation réduit le nombre d’allers et retours réseau entre le routeur et la partition, améliorant ainsi les performances. Actuellement, cette optimisation est effectuée pour les requêtes INSERT, SELECT, UPDATE et DELETE.
Rubriques
Exemples de requêtes à partition unique
Dans les exemples suivants, nous utiliserons la table partitionnée customers, avec la clé de partition customer_id et la table de référence zipcodes.
- SELECT
-
postgres_limitless=> EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM customers WHERE customer_id = 100; QUERY PLAN --------------------------------------------------------- Foreign Scan Output: customer_id, other_id, customer_name, balance Remote SQL: SELECT customer_id, other_id, customer_name, balance FROM public.customers WHERE (customer_id = 100) Single Shard Optimized (9 rows)postgres_limitless=> EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM orders LEFT JOIN zipcodes ON orders.zipcode_id = zipcodes.zipcode_id WHERE customer_id = 11; QUERY PLAN --------------------------------------------------------------------------------------------------------- Foreign Scan Output: customer_id, order_id, zipcode_id, customer_name, balance, zipcodes.zipcode_id, zipcodes.city Remote SQL: SELECT orders.customer_id, orders.order_id, orders.zipcode_id, orders.customer_name, orders.balance, zipcodes.zipcode_id, zipcodes.city FROM (public.orders LEFT JOIN public.zipcodes ON ((orders.zipcode_id = zipcodes.zipcode_id))) WHERE (orders.customer_id = 11) Single Shard Optimized (13 rows) - INSERT
-
postgres_limitless=> EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO customers (customer_id, other_id, customer_name, balance) VALUES (1, 10, 'saikiran', 1000); QUERY PLAN ------------------------------------------------------- Insert on public.customers -> Result Output: 1, 10, 'saikiran'::text, '1000'::real Single Shard Optimized (4 rows) - UPDATE
-
postgres_limitless=> EXPLAIN (VERBOSE, COSTS OFF) UPDATE orders SET balance = balance + 100 WHERE customer_id = 100; QUERY PLAN --------------------------------------------------------------------------------------------- Update on public.orders Foreign Update on public.orders_fs00002 orders_1 -> Foreign Update Remote SQL: UPDATE public.orders SET balance = (balance + (100)::double precision) WHERE (customer_id = 100) Single Shard Optimized (6 rows) - DELETE
-
postgres_limitless=> EXPLAIN (VERBOSE, COSTS OFF) DELETE FROM orders WHERE customer_id = 100 and balance = 0; QUERY PLAN --------------------------------------------------------------------- Delete on public.orders Foreign Delete on public.orders_fs00002 orders_1 -> Foreign Delete Remote SQL: DELETE FROM public.orders WHERE ((customer_id = 100) AND (balance = (0)::double precision)) Single Shard Optimized (6 rows)
Restrictions appliquées aux requêtes à partition unique
Les requêtes à partition unique sont soumises aux restrictions suivantes :
- Fonctions
-
Si une requête à partition unique contient une fonction, elle n’est éligible à l’optimisation à partition unique que si l’une des conditions suivantes est remplie :
-
La fonction est immuable. Pour plus d’informations, consultez Volatilité des fonctions.
-
La fonction est mutable, mais elle est enregistrée dans la vue
rds_aurora.limitless_distributed_functions. Pour plus d’informations, consultez Répartition des fonctions.
-
- Vues
-
Si une requête contient une ou plusieurs vues, l’optimisation à partition unique est désactivée si l’une des conditions suivantes est remplie :
-
N’importe quelle vue possède l’attribut
security_barrier. -
Les objets utilisés dans la requête nécessitent plusieurs privilèges utilisateur. Par exemple, une requête contient deux vues, lesquelles sont exécutées par deux utilisateurs différents.
CREATE VIEW v1 AS SELECT customer_name FROM customers c WHERE c.customer_id = 1; CREATE VIEW v2 WITH (security_barrier) AS SELECT customer_name FROM customers c WHERE c.customer_id = 1; postgres_limitless=> EXPLAIN VERBOSE SELECT * FROM v1; QUERY PLAN ------------------------------------------------------------------------------------ Foreign Scan (cost=100.00..101.00 rows=100 width=0) Output: customer_name Remote Plans from Shard postgres_s3: Seq Scan on public.customers_ts00001 c (cost=0.00..24.12 rows=6 width=32) Output: c.customer_name Filter: (c.customer_id = 1) Query Identifier: -6005737533846718506 Remote SQL: SELECT customer_name FROM ( SELECT c.customer_name FROM public.customers c WHERE (c.customer_id = 1)) v1 Query Identifier: -5754424854414896228 (12 rows) postgres_limitless=> EXPLAIN VERBOSE SELECT * FROM v2; QUERY PLAN -------------------------------------------------------------------------------------------- Foreign Scan on public.customers_fs00001 c (cost=100.00..128.41 rows=7 width=32) Output: c.customer_name Remote Plans from Shard postgres_s3: Seq Scan on public.customers_ts00001 customers (cost=0.00..24.12 rows=6 width=32) Output: customers.customer_name Filter: (customers.customer_id = 1) Query Identifier: 4136563775490008117 Remote SQL: SELECT customer_name FROM public.customers WHERE ((customer_id = 1)) Query Identifier: 5056054318010163757 (9 rows) -
- Instructions PREPARE et EXECUTE
-
Aurora PostgreSQL Limitless Database prend en charge l’optimisation à partition unique pour les instructions préparées
SELECT,UPDATEetDELETE.Cependant, lorsque des instructions préparées sont utilisées pour
PREPAREetEXECUTEalors queplan_cache_modeest défini sur'force_generic_plan', le planificateur de requêtes rejette l’optimisation à partition unique pour cette requête. - PL/pgSQL
-
Les requêtes contenant des variables PL/pgSQL sont exécutées sous forme d’instructions préparées implicites. Si une requête contient des variables PL/pgSQL, le planificateur de requêtes rejette l’optimisation à partition unique.
L’optimisation est prise en charge dans le bloc PL/pgSQL si l’instruction ne contient aucune variable PL/pgSQL.
Jointures entièrement qualifiées (explicites)
L’optimisation à partition unique est basée sur l’élimination des partitions. L’optimiseur PostgreSQL élimine les partitions en fonction de conditions constantes. Si Aurora PostgreSQL Limitless Database constate que toutes les partitions et tables restantes résident sur la même partition, elle indique que la requête est éligible à l’optimisation à partition unique. Toutes les conditions du filtre doivent être explicites pour que l’élimination des partitions fonctionne. Aurora PostgreSQL Limitless Database ne peut pas éliminer de partitions en l’absence d’un ou de plusieurs prédicats de jointure ou de filtrage portant sur les clés de partition de chaque table partitionnée de l’instruction.
Supposons que nous ayons partitionné les tables customers, orders et order_details en fonction de la colonne customer_id. Dans ce schéma, l’application essaie de conserver toutes les données d’un client sur une seule partition.
Considérons la requête suivante :
SELECT * FROM customers c, orders o, order_details od WHERE c.customer_id = o.customer_id AND od.order_id = o.order_id AND c.customer_id = 1;
Cette requête récupère toutes les données d’un client (c.customer_id = 1). Les données de ce client résident sur une seule partition, mais Aurora PostgreSQL Limitless Database ne considère pas cette requête comme une requête à partition unique. Le processus d’optimisation de la requête est le suivant :
-
L’optimiseur peut éliminer les partitions pour
customersetordersselon les conditions suivantes :c.customer_id = 1 c.customer_id = o.customer_id o.customer_id = 1 (transitive implicit condition) -
L’optimiseur ne peut éliminer aucune partition pour
order_details, car aucune condition constante n’est appliquée à la table. -
L’optimiseur détermine qu’il a lu toutes les partitions depuis
order_details. Par conséquent, la requête ne peut pas être qualifiée pour l’optimisation à partition unique.
Pour en faire une requête à partition unique, nous ajoutons la condition de jointure explicite suivante :
o.customer_id = od.customer_id
La requête modifiée se présente comme suit :
SELECT * FROM customers c, orders o, order_details od WHERE c.customer_id = o.customer_id AND o.customer_id = od.customer_id AND od. order_id = o. order_id AND c.customer_id = 1;
L’optimiseur peut désormais éliminer les partitions pour order_details. La nouvelle requête devient une requête à partition unique et est éligible à l’optimisation.
Configuration d’une clé de partition active
Cette fonctionnalité vous permet de définir une clé de partition unique lors de l’interrogation de la base de données, ce qui permet d’ajouter la clé de partition à toutes les requêtes SELECT et DML en tant que prédicat constant. Cette fonctionnalité est utile si vous avez migré vers Aurora PostgreSQL Limitless Database et que vous avez dénormalisé le schéma en ajoutant des clés de partition aux tables.
Vous pouvez ajouter automatiquement un prédicat de clé de partition à la logique SQL existante, sans modifier la sémantique des requêtes. L’ajout d’un prédicat de clé de partition actif n’est possible que sur les tables compatibles.
La fonctionnalité de clé de partition active utilise la variable rds_aurora.limitless_active_shard_key, dont la syntaxe est la suivante :
SET [session | local] rds_aurora.limitless_active_shard_key = '{"col1_value", "col2_value", ...}';
Quelques considérations concernant les clés de partition actives et les clés étrangères :
-
Une table partitionnée peut être soumise à une contrainte de clé étrangère lorsque les tables parente et enfant sont colocalisées et que la clé étrangère constitue un sur-ensemble de la clé de partition.
-
Une table partitionnée peut être soumise à une contrainte de clé étrangère vers une table de référence.
-
Une table de référence peut être soumise à une contrainte de clé étrangère vers une autre table de référence.
Prenons l’exemple d’une table partitionnée customers sur la colonne customer_id.
BEGIN; SET local rds_aurora.limitless_create_table_mode='sharded'; SET local rds_aurora.limitless_create_table_shard_key='{"customer_id"}'; CREATE TABLE customers(customer_id int PRIMARY KEY, name text , email text); COMMIT;
Lorsqu’une clé de partition active est définie, les requêtes subissent les transformations suivantes.
- SELECT
-
SET rds_aurora.limitless_active_shard_key = '{"123"}'; SELECT * FROM customers; -- This statement is changed to: SELECT * FROM customers WHERE customer_id = '123'::int; - INSERT
-
SET rds_aurora.limitless_active_shard_key = '{"123"}'; INSERT INTO customers(name, email) VALUES('Alex', 'alex@example.com'); -- This statement is changed to: INSERT INTO customers(customer_id, name, email) VALUES('123'::int, 'Alex', 'alex@example.com'); - UPDATE
-
SET rds_aurora.limitless_active_shard_key = '{"123"}'; UPDATE customers SET email = 'alex_new_email@example.com'; -- This statement is changed to: UPDATE customers SET email = 'alex_new_email@example.com' WHERE customer_id = '123'::int; - DELETE
-
SET rds_aurora.limitless_active_shard_key = '{"123"}'; DELETE FROM customers; -- This statement is changed to: DELETE FROM customers WHERE customer_id = '123'::int; - Jointures
-
Lorsque vous effectuez des opérations de jointure sur des tables ayant une clé de partition active, le prédicat de clé de partition est automatiquement ajouté à toutes les tables participant à la jointure. Cet ajout automatique du prédicat de clé de partition se produit uniquement lorsque toutes les tables de la requête appartiennent au même groupe de collocation. Lorsque des tables issues de plusieurs groupes de colocalisation sont impliquées dans la requête, le système renvoie une erreur.
Supposons en outre l’existence des tables
ordersetorder_details, qui sont colocalisées avec la tablecustomers.SET local rds_aurora.limitless_create_table_mode='sharded'; SET local rds_aurora.limitless_create_table_collocate_with='customers'; SET local rds_aurora.limitless_create_table_shard_key='{"customer_id"}'; CREATE TABLE orders (id int , customer_id int, total_amount int, date date); CREATE TABLE order_details (id int , order_id int, customer_id int, product_name VARCHAR(100), price int); COMMIT;Récupérez les 10 dernières factures de commande du client portant l’ID 10.
SET rds_aurora.limitless_active_shard_key = '{"10"}'; SELECT * FROM customers, orders, order_details WHERE orders.customer_id = customers.customer_id AND order_details.order_id = orders.order_id AND customers.customer_id = 10 order by order_date limit 10;Cette requête est transformée comme suit :
SELECT * FROM customers, orders, order_details WHERE orders.customer_id = customers.customer_id AND orders.order_id = order_details.order_id AND customers.customer_id = 10 AND order_details.customer_id = 10 AND orders.customer_id = 10 AND ORDER BY "order_date" LIMIT 10; - Tables compatibles avec les clés de partition actives
-
Le prédicat de clé de partition est ajouté uniquement aux tables compatibles avec la clé de partition active. Une table est considérée comme compatible si le nombre de colonnes de sa clé de partition correspond à celui indiqué dans la variable
rds_aurora.limitless_active_shard_key. Si la requête concerne des tables incompatibles avec la clé de partition active, le système génère une erreur au lieu de poursuivre la requête.Exemples :
-- Compatible table SET rds_aurora.limitless_active_shard_key = '{"10"}'; -- The following query works because the customers table is sharded on one column. SELECT * FROM customers; -- Incompatible table SET rds_aurora.limitless_active_shard_key = '{"10","20"}'; -- The following query raises a error because the customers table isn't sharded on two columns. SELECT * FROM customers;