Requirement
Say I have a key in Redis which holds a hash. I want to re-set the key with a new set of hash fields and values. There is no Redis command that does this today I believe (from https://stackoverflow.com/a/38791164/, https://stackoverflow.com/questions/48150251/).
Example
E.g. consider I have the following set of values
myKey foo bar
bla baz
There should be something in Redis that results in the following when I execute:
myKey qux quz
Work around today
For now we can pipe multiple commands (DEL and HSET) via a transaction (MULTI) and execute.
Silly and simple feature but looks good and reduces work overall. I was surprised to learn this didn't exist.
Comment From: nawfalhasan
A question, even if I wrap DEL and HSET in MULTI/EXEC statements, isn't this still 4 calls to Redis server?
- MULTI
- DEL
- HSET
- EXEC ?
Or does the redis-cli send the entire commands in one batch at the time i hit EXEC?
Comment From: gittyup2018
HMSET overwrites existing hash but for some reason it's being deprecated as of 4.0, it seems redis developers are not only not interesting in adding new features but also removing ones that do exist, I recommend keyDB which is based off redis and a simple drop in replacement and uses all cpu cores as default instead of redis's just 1.
https://keydb.dev/
Comment From: nawfalhasan
@gittyup2018 hmset doesnt do that as far as I know. It merely adds and updates input field-value pairs. To illustrate HMSET on my original example results in this:
myKey foo bar
bla baz
qux quz
Thanks for keydb tip. Does it solve this issue: https://github.com/antirez/redis/issues/6048 ? This is the most frustrating thing about Redis imo.
Comment From: mgravell
HMSET overwrites existing hash but for some reason it's being deprecated as of 4.0, it seems redis developers are not only not interesting in adding new features but also removing ones that do exist
Nothing has been removed; as the documentation explains quite clearly: HSET now allows varadic usage, so: there is no specific reason to use HMSET rather than HSET; HMSET still works just fine, though. HMSET also does not do the thing that you think it does; it has always been purely "upsert" - it does not remove fields that are not specified in the call to HMSET.
I'm not sure that "hey look, if I lie and mislead people about things: redis sounds terrible, come over here and use this other thing instead" is really entering into the proper spirit of things here, @gittyup2018
Comment From: mgravell
@nawfalhasan re 4 commands - keep in mind that 4 commands doesn't mean 4 round trips/latency fees; most clients allow some sort of "batch"/"pipeline"/"transaction" API, allowing you to send those 4 commands in a single contiguous block without waiting for the reply of each individually (but allowing you to access them afterwards). If you can be specific about which client you're using, we can probably be more specific in terms of how to do that.
Another option is to use Lua (EVAL/EVALSHA), although in this specific case, the MULTI/EXEC is probably simpler (since you don't need to check pre-conditions, which is when MULTI/EXEC ramps up in complexity)
As for where it is buffered: after issuing MULTI, your commands are buffered at the server until you issue EXEC or DISCARD; if you are using redis-cli, it is still sending each and waiting on the response each time - but: in many ways, redis-cli isn't necessarily representative of how client library access works; as I say, client libraries usually expose some kind of API for this scenario.
Comment From: nawfalhasan
@mgravell Thanks, I get it. Regarding the client I am using, its an obscure client you might not have heard of: StackExchange.Redis, tada.. :P
Comment From: mgravell
:) in that case;
var tran = db.CreateTransaction();
_ = tran.KeyDeleteAsync(key);
_ = tran.HashSetAsync(key, hashFields);
await tran.ExecuteAsync(); // or tran.Execute() for sync
Comment From: gittyup2018
Usually I ignore less intelligent comments from less intelligent people but I am curious what I lied about.
On the Redis website it states:
As per Redis 4.0.0, HMSET is considered deprecated. Please use HSET in new code.
Last I checked it's bad practice to use deprecated code that can be changed / removed:
In several fields, deprecation is the discouragement of use of some terminology, feature, design, or practice, typically because it has been superseded or is no longer considered efficient or safe, without completely removing it or prohibiting its use. - Wikipedia
Regarding multicore processor?
Redis is single-threaded with epoll/kqueue and scales indefinitely in terms of I/O concurrency. --@antirez (creator of Redis)
https://stackoverflow.com/questions/21304947/redis-performance-on-a-multi-core-cpu
On KeyDB's website:
KeyDB is fully multithreaded (not just IO) and as a result can use many machine cores to operate a single node. This is has enabled KeyDB to put our 5X the throughput of Redis. In order to get the same throughput with Redis, you would need to run a 7 node cluster on that same machine.
So next time before you rudely accuse someone, especially that you are not aware of, I suggest you -try- to use a little more intelligence and do your research first.
Comment From: nawfalhasan
@mgravell I guess it should be:
var tran = db.CreateTransaction();
var a = tran.KeyDeleteAsync(key);
var b = tran.HashSetAsync(key, hashFields);
await tran.ExecuteAsync(); // or tran.Execute() for sync
await a;
await b;
Comment From: antirez
@gittyup2018 Hi, you can use whatever project you want, however here you need to behave in a different way or I'll remove your comments and ban you.
Comment From: antirez
Nevermind on a second thought I blocked the user directly.
Comment From: antirez
"less intelligent comments from less intelligent people" is unacceptable here.
Comment From: rcmonitor
is unacceptable here.
It's a github, dude. "Unacceptable" is unacceptable here.