web-dev-qa-db-fra.com

La colonne Système "CTID" est-elle légitime pour identifier des lignes à supprimer?

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.

6
ruelloehr

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 alors SELECT 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:

7
Erwin Brandstetter