Les verrous garantissent l'isolation des transactions lors de l'exécution des instructions SQL. Hologres utilise à la fois des verrous Frontend (FE) et Backend (BE), chacun présentant des types, des étendues et des comportements de conflit distincts. Cette rubrique explique le fonctionnement de ces verrous et comment résoudre les problèmes liés aux verrous.
Contexte
Lorsqu'une requête est initiée dans Hologres, elle suit le chemin illustré dans la figure suivante.
Le Frontend analyse la requête, le moteur de requêtes génère un plan d'exécution et le moteur de stockage lit les données. Deux types de verrous interviennent dans ce processus.
-
Verrous Frontend (FE)
Le Frontend constitue la couche d'accès et est compatible avec le protocole PostgreSQL ; ses verrous sont donc également compatibles avec certains verrous PostgreSQL. Les verrous FE gèrent les métadonnées du FE.
-
Verrous Backend (BE)
Le BE englobe le moteur de requêtes et le Fixed Plan. Il utilise les propres verrous de Hologres, qui gèrent le schéma et les données du moteur de stockage.
Modifications du comportement des verrous
-
À partir de Hologres V2.0, un mécanisme sans verrou est activé par défaut dans le Frontend (FE). Cela signifie que si un conflit survient entre une instruction DDL et une instruction DQL sur la même table (par exemple, si une nouvelle requête est soumise alors qu'une opération DDL sur la Table A est en cours), la nouvelle requête DQL échouera immédiatement. Pour permettre aux nouvelles requêtes DQL d'attendre la libération du verrou au lieu d'échouer immédiatement, désactivez le paramètre GUC :
ALTER database <db_name> SET hg_experimental_disable_pg_locks = off; À partir de Hologres V2.1, le chargement massif de données dans une table sans clé primaire a été optimisé afin d'acquérir uniquement un verrou au niveau de la ligne plutôt qu'un verrou au niveau de la table.
Types de verrous
-
Verrous FE
La couche d'accès Hologres, le Frontend, est compatible avec PostgreSQL ; les verrous appliqués à ce niveau sont donc également compatibles avec PostgreSQL. PostgreSQL propose trois modes de verrouillage pour contrôler l'accès concurrent aux données : les verrous au niveau de la table, les verrous au niveau de la ligne et les verrous d'avertissement (advisory locks). Hologres prend en charge les verrous au niveau de la table ainsi que les verrous d'avertissement.
RemarqueHologres ne prend pas en charge le verrouillage explicite ni les fonctions définies par l'utilisateur (UDF) associées aux verrous d'avertissement.
-
Verrous au niveau de la table
-
Modes
Un verrou au niveau de la table s'applique à l'intégralité d'une table. Les modes disponibles sont décrits ci-dessous.
Mode de verrouillage
Description
Remarque
ACCESS SHARE
La commande
SELECTacquiert un verrou de ce mode sur les tables référencées.S.O.
ROW SHARE
Seules les commandes
SELECT FOR UPDATEetSELECT FOR SHAREacquièrent ce verrou sur la table cible. Les tables non ciblées (par exemple, les autres tables dans une jointure) n'acquièrent qu'un verrou ACCESS SHARE.Hologres ne prenant pas en charge les commandes
SELECT FOR UPDATEetSELECT FOR SHARE, ce mode de verrouillage ne s'applique pas.ROW EXCLUSIVE
Les commandes DML qui modifient les données, telles que
UPDATE,DELETEetINSERT, acquièrent ce verrou.Ce point doit être analysé conjointement avec les verrous BE.
SHARE UPDATE EXCLUSIVE
Ce verrou empêche les conflits entre
VACUUMet les modifications simultanées du schéma. Les commandes suivantes acquièrent ce verrou.-
lazy VACUUM(à l'exclusion deVacuum Full). -
ANALYZE. -
CREATE INDEX CONCURRENTLY.RemarqueLorsque Hologres exécute cette commande, il n'acquiert pas de verrou
SHARE UPDATE EXCLUSIVE. Il acquiert plutôt un verrouSHARE, à l'instar de la commandeCREATE INDEXnon concurrente. -
CREATE STATISTICS(non pris en charge par Hologres). -
COMMENT ON. -
ALTER TABLE VALIDATE CONSTRAINT(non pris en charge par Hologres). -
ALTER TABLE SET/RESET (storage_parameter). Hologres permet uniquement d'utiliser cette commande pour définir ses propres propriétés étendues ainsi que la propriété native PostgreSQLautovacuum_enabled. La définition de ces propriétés n'acquiert aucun verrou de table. La modification de certains autres paramètres de stockage intégrés à PostgreSQL acquiert ce verrou. Pour plus d'informations, consultez la rubrique ALTER TABLE. -
ALTER TABLE ALTER COLUMN SET/RESET options. -
ALTER TABLE SET STATISTICS(non pris en charge par Hologres). -
ALTER TABLE CLUSTER ON(non pris en charge par Hologres). -
ALTER TABLE SET WITHOUT CLUSTER(non pris en charge par Hologres).
Accordez une attention particulière à la commande
ANALYZE.SHARE
Seule la commande
CREATE INDEXnon concurrente acquiert ce verrou.RemarqueDans Hologres, la création d'un index JSON acquiert ce verrou.
Concentrez-vous sur la commande
CREATE INDEX(utilisée pour créer des index liés à JSON).SHARE ROW EXCLUSIVE
Ce verrou empêche les modifications de données simultanées. Les commandes suivantes l'acquièrent.
-
CREATE COLLATION(non pris en charge par Hologres). -
CREATE TRIGGER(non pris en charge par Hologres). -
Certaines commandes
ALTER TABLE.-
DISABLE/ENABLE [ REPLICA | ALWAYS ] TRIGGER(non pris en charge par Hologres). -
ADD table_constraint(non pris en charge par Hologres).
-
Hologres ne prenant pas en charge les commandes qui acquièrent ce verrou, ce mode de verrouillage ne s'applique pas.
EXCLUSIVE
Seule la commande
REFRESH MATERIALIZED VIEW CONCURRENTLYacquiert ce verrou.Hologres ne prenant pas en charge la commande
REFRESH MATERIALIZED VIEW CONCURRENTLY, ce mode de verrouillage ne s'applique pas.ACCESS EXCLUSIVE
Verrou requis pour un accès entièrement exclusif, entrant en conflit avec tous les autres verrous. Les commandes suivantes l'acquièrent.
-
DROP TABLE -
TRUNCATE TABLE -
REINDEX(non pris en charge par Hologres). -
CLUSTER(non pris en charge par Hologres). -
VACUUM FULL -
REFRESH MATERIALIZED VIEW (without CONCURRENTLY)(non pris en charge par Hologres). -
LOCK: la commande LOCK explicite. Si aucun type de verrou spécifique n'est indiqué, ce verrou est acquis par défaut (non pris en charge par Hologres). -
ALTER TABLE: hormis les formes deALTER TABLEqui acquièrent des verrous spécifiques mentionnés précédemment, les autres formes deALTER TABLEacquièrent ce verrou par défaut.
Il s'agit d'un verrou critique. Les opérations DDL dans Hologres acquièrent ce verrou, qui entre en conflit avec tous les autres types de verrous.
-
-
Délai d'expiration
Les verrous FE n'ont pas de délai d'expiration par défaut. Vous devez définir explicitement un délai d'expiration afin d'éviter des temps d'attente de verrou excessivement longs. Consultez la rubrique Gérer les requêtes.
-
Relations de conflit
Le tableau suivant présente les conflits entre les modes de verrouillage. Un conflit signifie qu'une opération doit attendre qu'une autre libère son verrou.
Remarqueindique l'absence de conflit. indique un conflit.
Requested lock mode
ACCESS SHARE
ROW SHARE
ROW EXCLUSIVE
SHARE UPDATE EXCLUSIVE
SHARE
SHARE ROW EXCLUSIVE
EXCLUSIVE
ACCESS EXCLUSIVE
ACCESS SHARE
ROW SHARE
ROW EXCLUSIVE
SHARE UPDATE EXCLUSIVE
SHARE
SHARE ROW EXCLUSIVE
EXCLUSIVE
ACCESS EXCLUSIVE
-
-
Verrou consultatif
Les verrous consultatifs ont des significations définies par l'application. Dans la plupart des scénarios métier Hologres, vous n'avez pas besoin de leur accorder une attention particulière.
-
-
Verrous BE
-
Catégories
Dans Hologres, les verrous BE sont classés comme suit.
Lock category
Introduction to locks
Exclusive(X)
Un verrou exclusif (ou verrou mutex) est acquis lorsqu'une transaction doit modifier des données, par exemple avec les commandes DML telles que
DELETE,INSERTouUPDATE. Un verrou exclusif ne peut être accordé que s'il n'existe aucun autre verrou partagé ou exclusif sur la ressource. Une fois acquis, aucun autre verrou ne peut être placé sur cette ressource.Shared(S)
Un verrou partagé est demandé lorsqu'une transaction doit lire des données, empêchant ainsi d'autres transactions de modifier les données en cours de lecture. Plusieurs verrous partagés peuvent coexister sur la même ressource, permettant aux commandes DQL de s'exécuter simultanément car elles ne modifient pas la ressource.
Intent(I)
Un verrou d'intention indique une structure de verrouillage hiérarchique, permettant à plusieurs verrous d'intention de coexister sur la même ressource. Après l'acquisition d'un verrou d'intention, un verrou exclusif ne peut plus être accordé pour cette ressource. Par exemple, lorsqu'une transaction demande un verrou exclusif sur une ligne, elle acquiert également un verrou d'intention sur la table, empêchant d'autres transactions d'obtenir un verrou exclusif sur la table.
-
Délai d'expiration
Le délai d'expiration par défaut pour les verrous BE est de 5 minutes.
-
Relation de conflit
Les conflits liés aux verrous BE sont décrits ci-dessous. Un conflit signifie qu'une opération doit attendre qu'une autre libère son verrou.
Remarqueindique l'absence de conflit. indique un conflit.
Operation
DROP
ALTER
SELECT
UPDATE
DELETE
INSERT (including INSERT ON CONFLICT)
DROP
ALTER
SELECT
UPDATE
DELETE
INSERT (including INSERT ON CONFLICT)
-
Portées des verrous
La portée d'un verrou varie selon sa catégorie.
-
Verrous FE
Les verrous FE affectent uniquement les objets de table, et non les données de la table. Un verrou est soit acquis, soit bloqué. Un état bloqué indique un conflit de verrou, ce qui signifie que l'opération est en attente du verrou.
-
Verrous BE
Les verrous BE affectent soit les données de la table, soit le schéma. Leurs portées sont les suivantes :
Verrous de données de table : Acquiert un verrou sur toutes les données d'une table. L'acquisition simultanée par plusieurs tâches peut provoquer des délais d'attente de verrou.
Verrou de données de ligne : Verrouille une ligne entière, ce qui améliore l'efficacité d'exécution. Les requêtes accélérées par Fixed Plan utilisent soit des verrous de données de ligne, soit des verrous de schéma de table.
-
Verrou de schéma de table : Verrouille le schéma de la table. Il est acquis par les transactions qui doivent lire ou modifier le schéma de la table. La plupart des transactions acquièrent un verrou de schéma. Types actuels de verrous de schéma :
SchX : Verrou exclusif de schéma, utilisé pour les instructions DDL. Actuellement, il prend uniquement en charge la commande
DROP TABLE.SchU : Verrou de mise à jour de schéma, utilisé pour les instructions DDL qui modifient la structure de la table, y compris les commandes
ALTER TABLEetset_table_property.SchE : Verrou d'existence de schéma, utilisé pour les instructions DML et DQL afin d'empêcher la suppression d'une table pendant les opérations de lecture et d'écriture.
RemarqueSchU offre un contrôle granulaire pour les verrous DDL, permettant aux requêtes DQL de s'exécuter normalement pendant les opérations
ALTER TABLEsans attendre. SchX est le verrou exclusif DDL le plus grossier, pour lequel toutes les opérations DDL, DML et DQL doivent attendre.Si une requête met beaucoup de temps à démarrer, elle est peut-être en attente de verrous BE.
Les portées des verrous pour les commandes courantes dans Hologres sont indiquées ci-dessous. indique que l'opération acquiert le verrou spécifié.
Les écritures, mises à jour et suppressions qui n'utilisent pas de Fixed Plan sont considérées comme des opérations Bulkload.
La commande
CREATE INDEXfait référence à la création d'index liés au JSON.Les commandes DDL incluent
CREATE,DROP,ALTER, etc.
|
Opération / Portée du verrou |
Verrou au niveau de la table |
Verrou de données de table |
Verrou de données de ligne |
Verrou de schéma de table |
|
CREATE |
|
N/A |
||
|
DROP |
Remarque
Une fois que la commande |
N/A |
N/A |
Remarque
Entre en conflit avec toutes les autres opérations. |
|
ALTER |
Remarque
Identique à la commande |
N/A |
N/A |
Remarque
Vous pouvez exécuter des commandes |
|
SELECT |
Remarque
Tant que le verrou de table est maintenu, les commandes |
N/A |
N/A |
Remarque
Lorsqu'une commande |
|
INSERT (y compris INSERT ON CONFLICT) |
Remarque
La commande |
Remarque
Bulkload entre en conflit avec Fixed Plan. |
Si l'opération est effectuée via Fixed Plan, un verrou de données de ligne est acquis. À partir de Hologres V2.1, l'opération Bulkload pour une table sans clé primaire acquiert également uniquement un verrou de données de ligne. Remarque
|
Remarque
Entre en conflit avec les opérations DDL et DML. |
|
UPDATE |
Remarque
Ce verrou entre en conflit avec |
Remarque
Entre en conflit avec les opérations DDL et DML. |
||
|
DELETE |
Remarque
Ce verrou entre en conflit avec |
Remarque
Entre en conflit avec les opérations DDL et DML. |
||
Comportement des verrous liés aux transactions
Hologres prend actuellement en charge les transactions explicites uniquement pour les instructions DDL. Il ne prend pas en charge les transactions DML pures ni les transactions mixtes combinant DDL et DML.
Hologres ne prend pas en charge les sous-transactions imbriquées.
-
Bien que les transactions DML pures soient acceptées syntaxiquement, elles ne prennent pas réellement en charge les validations (commit) et les annulations (rollback) atomiques.
Dans l'exemple DML suivant, même si l'instruction
INSERTréussit, les données insérées ne seront pas annulées si l'instructionUPDATEsuivante échoue.begin; insert into t1(id, salary) values (1, 0); update t1 set salary = 0.1 where id = 1; commit; -
Les transactions DDL pures fonctionnent comme prévu.
Si une commande DDL de la transaction échoue, l'intégralité de la transaction est annulée. Par exemple, dans le code ci-dessous, si la commande
ALTERéchoue, les opérationsCREATEetDROPprécédentes sont annulées.begin; create table t1(i int); drop table if exists t2; alter table t1 add column n text; commit; -
Les transactions mélangeant des commandes DDL et DML sont interdites.
Dans l'exemple suivant, lorsqu'une transaction contient à la fois des commandes DDL et DML, la commande DML génère une erreur.
begin; create table t1(i int); update t1 set i = 1 where i = 1; -- DML statement error ERROR: UPDATE in ddl transaction is not supported now. -
Les verrous acquis par toute commande au sein d'une transaction explicite ne sont libérés qu'à la fin de la transaction entière (par validation ou annulation).
Dans l'exemple suivant, une opération
ALTERsur une table parent acquiert des verrousACCESS EXCLUSIVEsur la table parent (login_history) et sur la table enfant (login_history_202001). Ces verrous ne sont pas libérés immédiatement après la fin de la commande. Ils sont conservés jusqu'à l'exécution duCOMMITfinal (qu'il réussisse ou échoue). Si leCOMMITn'est pas exécuté, les verrous sont conservés indéfiniment et toute autre opération DDL sur cette table sera bloquée et générera une erreur.-- suppose we have three tables create table temp1(i int, t text); create table login_history(ds text, user_id bigint, ts timestamptz) partition by list (ds); create table login_history_202001 partition of login_history for values in ('202001'); begin; alter table login_history_s1 add column user_id bigint; drop table temp1; create table tx2(i int); commit;
Dépannage des verrous FE
Suivez ces étapes pour vérifier et résoudre les verrous FE :
-
Si une requête prend beaucoup de temps, vérifiez le champ
wait_event_typepour voir si la requête est en attente d'un verrou.Dans l'exemple de commande suivant, si le champ
wait_event_typedans le résultat estLock, cela indique que la requête est en attente d'un verrou FE.-- Hologres V2.0 and later: select query,state,query_id,transaction_id,pid,wait_event_type,wait_event,running_info,extend_info FROM hg_stat_activity where query_id = 200640xxxx; -- The following result is returned: ----------------+---------------------------------------------------------------- query | drop table test_order_table1; state | active query_id | 200640xxxx pid | 123xx transaction_id | 200640xxxx wait_event_type | Lock wait_event | relation running_info | {"current_stage":{"stage_duration_ms":47383,"stage_name":"PARSING"},"fe_id":1,"warehouse_id":0}+ | extend_info | {} + -- Hologres V1.3 and earlier: select datname, pid, application_name, wait_event_type, state,query_start, query from pg_stat_activity where backend_type in ('client backend'); -- The following result is returned: ----------------+---------------------------------------------------------------- datname | holo_poc pid | 321xxx application_name | PostgreSQL JDBC Driver wait_event_type | lock state | active query_start |2023-04-20 14:31:46.989+08 query | delete from xxx -
Consultez le détenteur du verrou.
Syntaxe :
select * from pg_locks where pid = <pid>;Remplacez pid par la valeur
pidrenvoyée à l'étape 1. -
Identifiez le processus qui détient le verrou.
Si le résultat de l'étape 2 montre que la requête actuelle attend un verrou, utilisez la commande suivante avec l'
oid(ID d'objet) de la table pour trouver le processus qui détient un verrou dessus. Une valeurt(true) dans la colonnegrantedindique qu'un processus détient le verrou.-- Query the process that holds the table lock. select pid from pg_locks where relation = <OID> and granted = 't'; -
Identifiez la requête qui détient le verrou.
En utilisant le PID issu du résultat de l'étape 3, exécutez la commande suivante pour trouver la requête qui détient le verrou.
select * from pg_stat_activity where pid = <PID>; -
Libérez le verrou.
Exécutez la commande suivante pour terminer la requête et libérer le verrou.
select pg_cancel_backend(<pid>);
Dépannage des verrous BE
Si le champ be_lock_waiters dans la vue hg_stat_activity contient des données, la requête détient un verrou ou est bloquée par un verrou BE. Procédez au dépannage en suivant ces étapes.
hg_stat_activity est pris en charge uniquement dans Hologres V2.0 et versions ultérieures.
-
Scénario 1 : La requête actuelle détient un verrou et d'autres requêtes attendent sa libération.
Consultez la requête détenant le verrou et les requêtes bloquées :
select query_id, transaction_id, ((extend_info::json)->'be_lock_waiters'->>0)::text as be_lock_waiters FROM hg_stat_activity as h where h.state = 'active' and ((extend_info::json)->'be_lock_waiters')::text != ''; -- The following result is returned: ----------------+------------------ query_id | 10005xxx transaction_id | 10005xxx be_lock_waiters | 13235xxx -
Scénario 2 : Vérifiez quelle requête bloque la requête actuelle.
Déterminez quelle requête détient le verrou attendu par la requête actuelle.
select query_id, transaction_id, ((extend_info::json)->'be_lock_waiters')::text as be_lock_waiters FROM hg_stat_activity as h where h.state = 'active' and ((extend_info::jsonb)->'be_lock_waiters')::jsonb ? '10005xxx'; -[ RECORD 1 ]---+------------------------------------------ query_id | 200740017664xxxx transaction_id | 200740017664xxxx be_lock_waiters | ["200640051468xxxx","200540035746xxxx"]
Erreurs courantes et solutions
-
Erreur :
internal error: Cannot acquire lock in time, current owners: [(Transaction =302xxxx, Lock Mode = SchS|SchE|X)].Cause possible : Votre requête a expiré après avoir attendu un verrou BE pendant 5 minutes. Une autre requête détient un verrou incompatible (dans ce cas, une combinaison de verrous SchS, SchE et Exclusif) sur la même table.
Solution : Identifiez la requête bloquante et terminez-la. L'ID de transaction indiqué dans le message d'erreur,
Transaction =302xxxx, correspond à l'ID de la requête bloquante. Recherchez cet ID de requête dans le journal des requêtes lentes ou la vue des requêtes actives pour identifier et gérer le processus.
-
Erreur :
ERROR: The schema version update timed out because the server's current version (xxx) is older than the requested version (yyy).Cause possible : Une instruction DDL met d'abord à jour la version du schéma sur le FE. Si une nouvelle requête arrive avant que le moteur de stockage n'ait appliqué la modification, la requête doit patienter. Elle échoue si cette attente dépasse le délai d'expiration de 5 minutes.
-
Solution :
Terminez l'opération DDL qui détient le verrou, puis réexécutez votre requête.
Si le problème persiste, redémarrez l'instance pour forcer la synchronisation.
-
Erreur :
The requested table name: xxx (id: 10, version: 26) mismatches the version of the table (id: 10, version: 28) from server.Cause possible : Après une opération DDL, le moteur de stockage met à jour sa version, mais cette modification doit être répliquée sur tous les nœuds FE. Cette erreur se produit lorsque votre requête se connecte à un nœud FE qui n'a pas encore synchronisé la dernière version de la table depuis le moteur de stockage.
-
Solution :
Réessayez la requête plusieurs fois. Le problème se résout souvent lorsque vous vous connectez à un nœud FE mis à jour.
Si plusieurs tentatives restent infructueuses après quelques minutes, redémarrez l'instance pour effacer l'état incohérent.
-
Erreur :
internal error: Cannot find index full ID: 86xxx (table id: 20yy, index id: 1) in storages or it is deleting!.Cause possible : Cette erreur survient lorsqu'une opération DML (telle que
SELECTouDELETE) tente d'accéder à une table pendant qu'une commandeDROP TABLEouTRUNCATE TABLEest en cours d'exécution sur celle-ci. La requête DML attend la libération du verrou DDL, mais au moment de son exécution, la table ou son index a déjà été supprimé.Solution : Assurez-vous qu'aucune autre requête n'est en cours d'exécution sur une table avant d'y exécuter des commandes
DROPouTRUNCATE. Coordonnez les opérations DDL et DML pour éviter tout accès simultané.