Reputation: 1517
I want to get the number of keys for a certain prefix, similar:
count($redis->keys('user_*'));
But it is not suitable in the case of a large number of keys like this
Upvotes: 3
Views: 5483
Reputation: 6754
You can improve this using Lua scripts. See predis examples of using EVAL
here.
If you want to get them on one single command, the best you can do is
local keys = redis.call('KEYS', ARGV[1])
return table.getn(keys)
Use as:
EVAL "local keys = redis.call('KEYS', ARGV[1]) \n return table.getn(keys)" 0 user_*
But this will still block your server for as long as it scans the whole database, as Redis is single-threaded. You are saving here on buffering and network payload only.
To count without blocking your server for long, you can use SCAN
. This will basically break down the scanning of the database to little steps. First, you call with cursor
set to zero, and then pass the returned cursor on subsequent calls.
local keys = redis.call('SCAN', ARGV[1], 'MATCH', ARGV[2], 'COUNT', ARGV[3])
return {keys[1], table.getn(keys[2])}
Use as:
> EVAL "local keys = redis.call('SCAN', ARGV[1], 'MATCH', ARGV[2], 'COUNT', ARGV[3]) \n return {keys[1], table.getn(keys[2])}" 0 0 user_* 100
1) "1000"
2) (integer) 101
The three arguments passed after numkeys
are cursor
, pattern
and count
.
The first returned value is the next cursor
, the second integer value is the count of keys on this iteration.
For COUNT
value selection, see Is there any recommended value of COUNT for SCAN / HSCAN command in REDIS?.
See in Redic `SCAN`: how to maintain a balance between newcomming keys that might match and ensure eventual result in a reasonable time? how you can use the cursor to deduce a percentage of progress.
Upvotes: 3