Pour Cassandra, UPDATE
s 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+.
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 deINSERT
etUPDATE
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.
Malheureusement, la réponse acceptée n'est pas exacte à 100%. insert
s sont différents de update
s:
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 update
s.
insert
s crée un marqueur de ligne en direct , tandis que update
s 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.
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.