Skip to content

Instantly share code, notes, and snippets.

@itamarhaber
Last active December 14, 2023 14:14
Show Gist options
  • Save itamarhaber/d30b3c40a72a07f23c70 to your computer and use it in GitHub Desktop.
Save itamarhaber/d30b3c40a72a07f23c70 to your computer and use it in GitHub Desktop.
The fastest, type-agnostic way to copy a Redis key, as discussed in https://redislabs.com/blog/the-7th-principle-of-redis-we-optimize-for-joy
-- @desc: The fastest, type-agnostic way to copy a Redis key
-- @usage: redis-cli --eval copy_key.lua <source> <dest> , [NX]
local s = KEYS[1]
local d = KEYS[2]
if redis.call("EXISTS", d) == 1 then
if type(ARGV[1]) == "string" and ARGV[1]:upper() == "NX" then
return nil
else
redis.call("DEL", d)
end
end
redis.call("RESTORE", d, 0, redis.call("DUMP", s))
return "OK"
foo@bar:~$ redis-benchmark -r 10000000 -n 10000000 -P 1000 lpush L __rand_int__
====== lpush L __rand_int__ ======
10000000 requests completed in 1.30 seconds
814929.50 requests per second
foo@bar:~$ redis-cli llen L
(integer) 10030000
-- @desc: copies a list with POP and PUSH
-- @usage: redis-cli --eval copy_list_with_popnpush.lua <source> <dest>
local s = KEYS[1]
local d = KEYS[2]
local l = redis.call("LLEN", s)
local i = tonumber(l)
while i > 0 do
local v = redis.call("RPOPLPUSH", s, s)
redis.call("LPUSH", d, v)
i = i - 1
end
return l
foo@bar:~$ time redis-cli --eval copy_list_with_popnpush.lua L T
(integer) 10030000
real 0m23.579s
user 0m0.000s
sys 0m0.006s
-- @desc: copies a list with LRANGE
-- @usage: redis-cli --eval copy_list_with_lrange.lua <source> <dest>
local s = KEYS[1]
local d = KEYS[2]
local i = tonumber(redis.call("LLEN", s))
local j = 0
while j < i do
local l = redis.call("LRANGE", s, j, j+99)
redis.call("LPUSH", d, unpack(l))
j = j + 100
end
foo@bar:~$ redis-cli del T
(integer) 1
foo@bar:~$ time redis-cli --eval copy_list_with_lrange.lua L T
(integer) 10030000
real 0m11.148s
user 0m0.000s
sys 0m0.004s
foo@bar:~$ redis-cli del T
(integer) 1
foo@bar:~$ time redis-cli sort L by nosort store T
(integer) 10030000
real 0m2.390s
user 0m0.000s
sys 0m0.003s
foo@bar:~$ redis-cli del T
(integer) 1
foo@bar:~$ time redis-cli --eval copy_key.lua L T
"OK"
real 0m1.661s
user 0m0.000s
sys 0m0.007s
@itamarhaber
Copy link
Author

RESTORE's new REPLACE modifier could be used instead of the NX-triggered DEL, but the latter is employed in this script to ensure compatibility with older versions.

@itamarhaber
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment