Lua script syntax in Redis - Time & Space Complexity
When running Lua scripts in Redis, it's important to know how the time taken grows as the script processes more data.
We want to understand how the script's execution time changes when the input size changes.
Analyze the time complexity of the following Lua script in Redis.
local key = KEYS[1]
local count = tonumber(ARGV[1])
for i = 1, count do
redis.call('LPUSH', key, i)
end
return redis.call('LLEN', key)
This script pushes numbers from 1 to count into a Redis list and then returns the list length.
Look for repeated actions in the script.
- Primary operation: The loop runs redis.call('LPUSH') repeatedly.
- How many times: Exactly
counttimes, once for each number pushed.
As the count grows, the number of push operations grows the same way.
| Input Size (count) | Approx. Operations |
|---|---|
| 10 | 10 LPUSH calls + 1 LLEN call |
| 100 | 100 LPUSH calls + 1 LLEN call |
| 1000 | 1000 LPUSH calls + 1 LLEN call |
Pattern observation: The number of operations grows directly with the input size.
Time Complexity: O(n)
This means the script takes longer roughly in direct proportion to how many items it processes.
[X] Wrong: "The script runs in constant time no matter how many items are pushed."
[OK] Correct: Each LPUSH call adds work, so more items mean more time.
Understanding how Lua scripts scale in Redis helps you write efficient scripts and explain their performance clearly.
"What if the script used RPUSH instead of LPUSH? How would the time complexity change?"
Practice
EVAL command?Solution
Step 1: Understand EVAL syntax
The EVAL command requires a Lua script as a string, followed by the number of keys and then the keys and arguments.Step 2: Check correct Lua script format
The Lua script must be a string and useredis.callto execute Redis commands, e.g.,return redis.call("PING").Final Answer:
EVAL 'return redis.call("PING")' 0 -> Option BQuick Check:
EVAL with Lua string and 0 keys = A [OK]
- Not passing Lua code as a string
- Missing return statement in Lua script
- Incorrect number of keys argument
- Using Redis commands directly without redis.call
SET inside a Lua script?Solution
Step 1: Recall Redis Lua API
In Lua scripts for Redis, commands are called usingredis.callwith the command name as first argument.Step 2: Check syntax correctness
The correct syntax isredis.call('SET', 'key', 'value'). Other options misuse the API or method calls.Final Answer:
redis.call('SET', 'key', 'value') -> Option AQuick Check:
Use redis.call('COMMAND', args...) = B [OK]
- Using dot notation like redis.SET
- Swapping order of arguments
- Using call.redis instead of redis.call
- Missing quotes around command name
EVAL in Redis?return redis.call('INCR', KEYS[1])Assuming the key
counter does not exist before and the script is called with KEYS[1] = 'counter'.Solution
Step 1: Understand INCR behavior on non-existing key
INCR command creates the key with value 0 then increments it by 1, so the new value is 1.Step 2: Return value of redis.call('INCR', key)
The call returns the new value after increment, which is 1.Final Answer:
1 -> Option DQuick Check:
INCR on new key returns 1 [OK]
- Assuming INCR returns 0 on new key
- Expecting nil for missing key
- Confusing return value with command success
- Not passing KEYS argument correctly
local val = redis.call('GET', KEYS[1])
if val == nil then
redis.call('SET', KEYS[1], '1')
else
redis.call('INCR', KEYS[1])
end
return redis.call('GET', KEYS[1])Solution
Step 1: Review the script logic
The script fetches the value with GET. If nil, sets to '1'; else calls INCR, then returns the final GET.Step 2: Spot the problem with INCR
redis.call('INCR', KEYS[1])will raise an error if the key's existing value is a non-integer string (e.g., 'abc'). The script does not validate the value type before incrementing.Step 3: Rule out other options
There is a return statement (not B), local variables are allowed in Redis Lua (not C), and KEYS[1] uses correct 1-based indexing (not D).Final Answer:
Using redis.call('INCR') on a string value causes error -> Option CQuick Check:
INCR errors on non-integer strings [OK]
- Thinking INCR fails on string '1'
- Confusing local variable usage
- Assuming missing return statement
- Misusing KEYS index
-- Option A
if redis.call('EXISTS', KEYS[1]) == 1 then
return redis.call('INCR', KEYS[1])
else
return nil
end
-- Option B
return redis.call('INCR', KEYS[1])
-- Option C
if redis.call('GET', KEYS[1]) then
redis.call('INCR', KEYS[1])
end
return redis.call('GET', KEYS[1])
-- Option D
if redis.call('EXISTS', KEYS[1]) == 0 then
return redis.call('INCR', KEYS[1])
else
return nil
endSolution
Step 1: Understand requirement
Increment counter only if it exists. If not, return nil without creating it.Step 2: Analyze the scripts
The script checkingredis.call('EXISTS', KEYS[1]) == 1then returningredis.call('INCR', KEYS[1])elsenilmatches exactly.
One script calls INCR unconditionally, creating if missing.
Another checks ifredis.call('GET', KEYS[1])(truthy for any non-nil), calls INCR but returns subsequent GET (may error on non-integers or not return increment directly).
The last increments ifEXISTS == 0, opposite of needed.Final Answer:
Option A -> Option AQuick Check:
Check EXISTS before INCR to avoid creating key [OK]
- Incrementing without checking key existence
- Using EXISTS == 0 to increment
- Not returning correct value after increment
- Using GET without handling nil properly
Ready to prove it?
Pass the test and this pattern moves unknown
