web-dev-qa-db-fra.com

Une MISE À JOUR devient-elle un INSERT implicite

Pour Cassandra, UPDATEs devient-il un INSERT implicite si la ligne sélectionnée n'existe pas? Autrement dit, si je dis

 UPDATE users SET name = "Raedwald" WHERE id = 545127

et id est le PRIMARY KEY de la table users, et la table n'a pas de ligne avec une clé de 545127, sera-ce équivalent à

 INSERT INTO users (id, name) VALUES (545127, "Raedwald")

Je sais que l'inverse est vrai: un INSERT pour un id qui existe déjà devient un UPDATE de la ligne avec ce id. Plus ancien Cassandra parlait des insertions comme étant des "upserts" pour cette raison.

Je suis intéressé par le cas de CQL3, Cassandra version 1.2+.

38
Raedwald

Oui, pour Cassandra UPDATE est synonyme de INSERT, comme expliqué dans la documentation CQL où il dit ce qui suit à propos de UPDATE:

Notez que contrairement à SQL, UPDATE ne vérifie pas l'existence antérieure de la ligne: la ligne est créée s'il n'en existait pas auparavant, et mise à jour sinon. De plus, il n'y a aucun moyen de savoir lequel de la création ou de la mise à jour s'est produit. En fait, la sémantique de INSERT et UPDATE est identique.

Pour que la sémantique soit différente, Cassandra devrait faire une lecture pour savoir si la ligne existe déjà. Cassandra est optimisée en écriture, vous pouvez donc toujours supposer il ne fait pas de lecture avant l'écriture sur aucune opération d'écriture. La seule exception concerne les compteurs (sauf sireplicate_on_write = false), auquel cas la réplication sur incrément implique une lecture.

40
Richard

Malheureusement, la réponse acceptée n'est pas exacte à 100%. inserts sont différents de updates:

cqlsh> create table ks.t (pk int, ck int, v int, primary key (pk, ck));
cqlsh> update ks.t set v = null where pk = 0 and ck = 0;
cqlsh> select * from ks.t where pk = 0 and ck = 0;

 pk | ck | v
----+----+---

(0 rows)
cqlsh> insert into ks.t (pk,ck,v) values (0,0,null);
cqlsh> select * from ks.t where pk = 0 and ck = 0;

 pk | ck | v
----+----+------
  0 |  0 | null

(1 rows)

Scylla fait la même chose.

Dans Scylla et Cassandra sont des séquences de cellules . Chaque colonne obtient une cellule correspondante (ou un ensemble de cellules dans le cas des collections non gelées ou des UDT). Mais il y a une cellule invisible supplémentaire - le marqueur de ligne (au moins en Scylla; je soupçonne = Cassandra a quelque chose de similaire).

Le marqueur de ligne fait une différence pour les lignes dans lesquelles toutes les autres cellules sont mortes: une ligne apparaît dans une requête si et seulement s'il y a au moins une cellule vivante. Ainsi, si le marqueur de ligne est vivant, la ligne apparaîtra, même si toutes les autres colonnes étaient précédemment définies sur null en utilisant par exemple updates.

inserts crée un marqueur de ligne en direct , tandis que updates ne touche pas le marqueur de ligne, il est donc clairement différent . L'exemple ci-dessus illustre cela. On pourrait soutenir que les marqueurs de ligne sont "internes" à Cassandra/Scylla, mais comme vous pouvez le voir, leurs effets sont visibles. Les marqueurs de ligne affectent votre vie, que cela vous plaise ou non, il peut donc être utile de vous en souvenir.

Il est triste qu'aucune documentation ne mentionne les marqueurs de ligne (enfin, j'ai trouvé ceci: https://docs.scylladb.com/architecture/sstable/sstable2/sstable-data-file/#cql-row-marker mais c'est dans le contexte de l'explication des internes de SSTable, qui est probablement dédié aux développeurs Scylla plus qu'aux utilisateurs).

Bonus: une suppression de cellule :

delete v from ks.t where pk = 0 and ck = 0

est identique à une mise à jour null:

update ks.t set v = null where pk = 0 and ck = 0

en effet, une suppression de cellule ne touche pas non plus le marqueur de ligne. Il définit uniquement la cellule spécifiée sur null.

Ceci est différent d'une suppression de ligne :

delete from ks.t where pk = 0 and ck = 0

car la ligne supprime insérer une pierre tombale de ligne , qui tue toutes les cellules de la ligne (y compris le marqueur de ligne). Vous pourriez dire que les suppressions de lignes sont l'opposé d'une insertion. Les mises à jour et les suppressions de cellules se situent quelque part entre les deux.

17
kbr

Ce que l'on peut faire est cependant ceci:

UPDATE table_name SET field = false WHERE key = 55 IF EXISTS;

Cela garantira que votre mise à jour est une véritable mise à jour et non un upsert.

15
KingOfHypocrites