1 Исследуйте очки знаний
Знания, рассматриваемые в этом вопросе, следующие:
- Разница между ключами и сканированием
- Недостатки запросов ключей
- Как используется сканирование?
- Особенности запросов сканирования
2 идеи решения
- Проблемы с запросом ключей
- Использование сканирования
- Особенности сканирования
3 Ключи, связанные с использованием
1) Ключи используются следующим образом
2) Проблемы с ключами
- Эта команда не имеет функции подкачки, мы можем запрашивать только все квалифицированные значения ключей одновременно, если результат запроса очень большой, то и выходная информация будет очень большой;
- Команда keys представляет собой обходной запрос, поэтому сложность его запроса по времени равна o(n), поэтому чем больше объем данных, тем дольше время запроса.
4 Сканирование, связанное с использованием
Давайте сначала смоделируем массивные данные и воспользуемся конвейером для добавления фрагментов данных 10 Вт. Код Java реализован следующим образом:
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import utils.JedisUtils;
public class ScanExample {
public static void main(String[] args) {
// 添加 10w 条数据
initData();
}
public static void initData(){
Jedis jedis = JedisUtils.getJedis();
Pipeline pipe = jedis.pipelined();
for (int i = 1; i < 100001; i++) {
pipe.set("user_token_" + i, "id" + i);
}
// 执行命令
pipe.sync();
System.out.println("数据插入完成");
}
}
Давайте запросим данные с идентификатором пользователя 9999 *. Команда сканирования используется следующим образом:
127.0.0.1:6379> scan 0 match user_token_9999* count 10000
1) "127064"
2) 1) "user_token_99997"
127.0.0.1:6379> scan 127064 match user_token_9999* count 10000
1) "1740"
2) 1) "user_token_9999"
127.0.0.1:6379> scan 1740 match user_token_9999* count 10000
1) "21298"
2) 1) "user_token_99996"
127.0.0.1:6379> scan 21298 match user_token_9999* count 10000
1) "65382"
2) (empty list or set)
127.0.0.1:6379> scan 65382 match user_token_9999* count 10000
1) "78081"
2) 1) "user_token_99998"
2) "user_token_99992"
127.0.0.1:6379> scan 78081 match user_token_9999* count 10000
1) "3993"
2) 1) "user_token_99994"
2) "user_token_99993"
127.0.0.1:6379> scan 3993 match user_token_9999* count 10000
1) "13773"
2) 1) "user_token_99995"
127.0.0.1:6379> scan 13773 match user_token_9999* count 10000
1) "47923"
2) (empty list or set)
127.0.0.1:6379> scan 47923 match user_token_9999* count 10000
1) "59751"
2) 1) "user_token_99990"
2) "user_token_99991"
3) "user_token_99999"
127.0.0.1:6379> scan 59751 match user_token_9999* count 10000
1) "0"
2) (empty list or set)
Из приведенных выше результатов выполнения мы видим две проблемы:
- Результат запроса пуст, но значение курсора не равно 0, что указывает на то, что обход не завершен;
- Счетчик установлен на 10000, но число, возвращаемое каждый раз, не равно 10000 и не является фиксированным, потому что count ограничивает только количество слотов словаря (приблизительно равное), которые сервер проходит за один раз, а не count значение возвращаемого результата.
Соответствующий синтаксис:scan cursor [MATCH pattern] [COUNT count]
в:
- курсор: позиция курсора, целочисленное значение, начиная с 0 и заканчивая 0, результат запроса пуст, но значение курсора не равно 0, что указывает на то, что обход не закончился;
- шаблон соответствия: обычное поле соответствия;
- count: ограничивает количество слотов словаря (приблизительно равно), которые сервер проходит за раз. Это просто подсказка для команды инкрементной итерации, а не максимальное количество возвращаемых результатов запроса. Значение по умолчанию — 10.
5 Боевой код сканирования
В этой статье мы используем код Java для реализации функции запроса сканирования.Код выглядит следующим образом:
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;
import utils.JedisUtils;
public class ScanExample {
public static void main(String[] args) {
Jedis jedis = JedisUtils.getJedis();
// 定义 match 和 count 参数
ScanParams params = new ScanParams();
params.count(10000);
params.match("user_token_9999*");
// 游标
String cursor = "0";
while (true) {
ScanResult<String> res = jedis.scan(cursor, params);
if (res.getCursor().equals("0")) {
// 表示最后一条
break;
}
cursor = res.getCursor(); // 设置游标
for (String item : res.getResult()) {
// 打印查询结果
System.out.println("查询结果:" + item);
}
}
}
}
Результат выполнения вышеуказанной программы следующий:
Результат запроса: user_token_99997
Результат запроса: user_token_9999
Результат запроса: user_token_99996
Результат запроса: user_token_99998
Результат запроса: user_token_99992
Результат запроса: user_token_99994
Результат запроса: user_token_99993
Результат запроса: user_token_99995
Результат запроса: user_token_99990
Результат запроса: user_token_99991
Результат запроса: user_token_99999
6 Резюме
Из этой статьи мы узнали, что если вы хотите запросить определенные данные в массиве данных данных в Redis, вам следует использовать сканирование.Сканирование имеет следующие характеристики:
- Scan может реализовать функцию сопоставления ключей;
- Scan выполняет запрос через курсор и не приводит к зависанию Redis;
- Scan предоставляет параметр count, который может указывать количество обходов;
- Scan вернет курсор клиенту, а пользовательский клиент продолжит выполнение запроса;
- Результаты, возвращаемые Scan, могут содержать повторяющиеся данные, что требует от клиента дедупликации;
- Однократное возвращение нулевого значения и курсор не равен 0 указывает на то, что обход не закончился;
- Сканирование может гарантировать, что удаленные элементы не будут запрашиваться перед началом поиска;
- Если элемент изменяется во время итерации, Scan не гарантирует, что соответствующий элемент может быть запрошен.
7 Видеоверсия
Содержание видео следующее:воооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооо
Следуйте QR-коду ниже, чтобы подписаться на более интересный контент.