When we use zadd command to update the score for exists value,if the score delta is small,element rank will be no change,i think we only need change the score, while deleting and reinserting is unnecessary.
To be sure the rank is not changed, we can use current node's forward and backward pointer to access the sibling nodes, to test whether the new score is still between the score of prev and next node.
The following source code is clipped from current redis repo.
int zsetAdd(robj *zobj, double score, sds ele, int *flags, double *newscore) {
...
/* Remove and re-insert when score changes. */
if (score != curscore) {
zskiplistNode *node;
serverAssert(zslDelete(zs->zsl,curscore,ele,&node));
znode = zslInsert(zs->zsl,score,node->ele);
/* We reused the node->ele SDS string, free the node now
* since zslInsert created a new one. */
node->ele = NULL;
zslFreeNode(node);
/* Note that we did not removed the original element from
* the hash table representing the sorted set, so we just
* update the score. */
dictGetVal(de) = &znode->score; /* Update score ptr. */
*flags |= ZADD_UPDATED;
}
...
Comment From: antirez
Very interesting optimization! I just wrote an implementation, stress testing it and committing tomorrow.
Comment From: antirez
P.S. Just pushed on faster-zadd branch here at Github.
Comment From: antirez
UPDATE: I'm merging the change, because I can measure a speed boost of more than 10% in an use case which is not even optimal to stress the optimization well enough, so it looks like it's worth it. Thanks @pyloque for the hint.
Comment From: daydayup825
hello da lao
Comment From: liwen2555376
nice!
Comment From: greedycat120
👍
Comment From: LyreBoss
🐂
Comment From: oranagra
i see the code that implements it is already merged. closing.
Comment From: blankjee
👍
Comment From: radiocontroller
👍