J'ai une table avec des centaines de millions de lignes que je dois supprimer des données de.
Les indices existants sont les plus efficaces.
Je peux cependant utiliser les index existants pour trouver les lignes à supprimer à l'aide des valeurs ctid
:
DELETE FROM calendar_event WHERE ctid IN
(SELECT ctid FROM calendar_event WHERE user_id = 5 LIMIT 100 FOR UPDATE)
Quels sont les risques de compter sur le ctid
dans ce cas? Mon pire des cas Scénario est en train de supprimer le mauvais rang.
Le ROW SHARE
verrouillage prise par FOR UPDATE
empêche l'accès en écriture simultanée qui changerait l'emplacement physique de la ligne. le manuel :
Cela les empêche d'être verrouillé, modifié ou supprimé par d'autres transactions jusqu'à la fin de la transaction en cours. C'est-à-dire d'autres transactions qui tentent
UPDATE
,DELETE
,SELECT FOR UPDATE
,SELECT FOR NO KEY UPDATE
,SELECT FOR SHARE
ou alorsSELECT FOR KEY SHARE
de ces lignes sera bloquée jusqu'à la fin de la transaction en cours;
Donc, le ctid
doit être stable pour la durée de la commande (ou la transaction, même si vous modifiez la ligne dans la même transaction vous-même. ctid
est toujours une colonne système à usage interne et le projet n'offrira aucune garantie. Si vous avez TOUT unique (combinaison de) colonne (s) (y compris le PK), utilisez-le au lieu du ctid
.
Cependant, j'utiliserais un CTE pour matérialiser la sélection et éviter les résultats inattendus.
Et sans ORDER BY
Vous sélectionnez des lignes arbitraires pour la suppression. Vous pourriez aussi bien ajouter SKIP LOCKED
Pour minimiser la conflit de verrouillage avec des transactions simultanées:
WITH cte AS (
SELECT ctid
FROM calendar_event
WHERE user_id = 5
LIMIT 100
FOR UPDATE SKIP LOCKED
)
DELETE FROM calendar_event WHERE ctid IN (TABLE cte);
Liés, avec explication pour les deux considérations:
À propos de ctid
: