背景
最近在做公司项目时遇到这样一个场景:
需要从Redis有序集合中取出20个元素,并且附带对应的score。
因为有mGet
、hMGet
等方便的指令,我下意识地在键盘上输入zMScore
,可奈何phpredis扩展
中不带有这儿方法,查阅资料之后,发现Redis本生就不带有这个方法。
问题
背景所述的Redis操作时放在接口中的,采用for循环用zScore
操作必然会加大程序和Redis的数据交互次数,导致接口速度变慢。
思考
1、类似于MySQL,Redis也是支持事务的,利用multi
和exec
操作将20个zScore
包起来;
2、编写Lua脚本,利用eval
方法进行操作;
实践
代码
- for循环方式
<?php
$redis = new \Redis();
$redis->connect('127.0.0.1', '6379');
$result = array();
$timeBegin = microtime(true);
for($i = 0; $i < 20; $i++) {
$key = 'test' . $i;
$result[$key] = (int)$redis->zScore('testSSet', $key);
}
$timeEnd = microtime(true);
var_dump($timeEnd - $timeBegin);
- 事务方式
<?php
$redis = new \Redis();
$redis->connect('127.0.0.1', '6379');
$result = array();
$timeBegin = microtime(true);
$redis->multi();
for($i = 0; $i < 20; $i++) {
$key = 'test' . $i;
$redis->zScore('testSSet', $key);
}
$result = $redis->exec();
$timeEnd = microtime(true);
var_dump($timeEnd - $timeBegin);
- eval方式
<?php
$redis = new \Redis();
$redis->connect('127.0.0.1', '6379');
$script = "return {%s}";
$keys = array();
$strs = array();
$timeBegin = microtime(true);
for($i = 0; $i < 20; $i++) {
$index = $i + 1;
$key = 'test' . $i;
$keys[] = $key;
$strs[] = "KEYS[{$index}]";
$strs[] = "redis.call('zScore', 'testSSet', KEYS[{$index}])";
}
$script = sprintf($script, implode(',', $strs));
$result = $redis->eval($script, $keys, 20);
$timeEnd = microtime(true);
var_dump($timeEnd - $timeBegin);
结果
- for循环方式:关键部分的耗时平均在0.6ms;
- 事务方式:关键部分的耗时平均在0.6ms;
- eval方式:关键部分的耗时平均在0.2ms;