1.列举常见的关系型数据库和非关系型都有那些?
关系型数据库(需要有表结构)
mysql、oracle 、 spl、server、db2、sybase
非关系型数据库(是以key-value存储的,没有表结构)(NoSQL)
(1) MongoDB
MongoDB 是一个高性能,开源,无模式的文档型数据库,开发语言是C++。它在许多场景下可用于替代传统的关系型数据库或键/值存储方式。
(2) Redis
Redis 是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。目前由VMware主持开发工作。

(3)mongo redis的区别
Mongo
它是一个内存数据库,数据都是放在内存里面的。
对数据的操作大部分都在内存中,但mongodb并不是单纯的内存数据库。
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组.
持久化方式:
mongodb的所有数据实际上是存放在硬盘的,所有要操作的数据通过mmap的方式映射到内存某个区域内。
然后,mongodb就在这块区域里面进行数据修改,避免了零碎的硬盘操
作。
redis:
它就是一个不折不扣的内存数据库了。
持久化方式:
redis所有数据都是放在内存中的,持久化是使用RDB方式或者aof方式。
无论数据还是索引都存放在硬盘中。到要使用的时候才交换到内存中。能够处理远超过内存总量的数据。

MYSQL
关系型数据库。
在不同的引擎上有不同 的存储方式。
查询语句是使用传统的 SQL 语句,拥有较为成熟的体系,成熟度很高。
开源数据库的份额在不断增加,MySQL 的份额页在持续增长。
缺点就是在海量数据处理的时候效率会显著变慢。
2.MySQL常见数据库引擎及比较?
‘Myisam’:
#支持全文索引
#查询速度相对较快
#支持表锁
#表锁:select * from tb for update;(锁:for update)
‘InnoDB’:
#支持事务
#支持行锁、表锁
#表锁:select * from tb for update;(锁:for update)
#行锁: select id ,name from tb where id=2 for update;(锁:for update)

3.简述数据三大范式?
#数据库的三大特性:
‘实体’:表
‘属性’:表中的数据(字段)
‘关系’:表与表之间的关系

#数据库设计三大范式:
‘第一范式(1NF)’
数据表中的每一列(每个字段),必须是不可拆分的最小单元
也就是确保每一列的原子性。
‘第二范式(2NF)’
满足第一范式后(1NF),要求表中的所有列,都必须依赖于主键,
而不能有任何一列 与主键没有关系,也就是说一个表只描述一件事。
‘第三范式(3NF)’
必须先满足第二范式(2NF)
要求:表中每一列只与主键直接相关而不是间接相关(表中每一列只能依赖于主键)
比如在设计一个订单数据表的时候,可以将客户编号作为一个外键和订单表建立相应的关系。
而不可以在订单表中添加关于客户其它信息(比如姓名、所属公司等)的字段。
数据库五大约束’
1.primary KEY:设置主键约束;
2.UNIQUE:设置唯一性约束,不能有重复值;
3.DEFAULT 默认值约束
4.NOT NULL:设置非空约束,该字段不能为空;
5. FOREIGN key :设置外键约束。

4.什么是事务?MySQL如何支持事务?
‘什么是事务’
事务由一个或多个sql语句组成一个整体;
在事务中的操作,要么都执行修改,要么都不执行,
只有在该事务中所有的语句都执行成功才会将修改加入到数据库中,否则回滚到上一步。
‘Mysql实现事务’
InnoDB支持事务,MyISAM不支持

# 启动事务:
    # start transaction;
    # update from account set money=money-100 where name='a';
    # update from account set money=money+100 where name='b';
    # commit;
    'start transaction 手动开启事务,commit 手动关闭事务'

5.简述数据库设计中一对多和多对多的应用场景?
FK(一对多)
下拉框里面的数据就需要用FK关联另一张表
M2M(多对多)
多选的下拉框,或者checkbox
一对多关系、多对一关系和一对一关系至少都有一侧是单个实体,所以记录之间的联系通过外键实现,让外键指向这个实体。
6.如何基于数据库实现商城商品计数器?
7.常见SQL(必备)
详见武沛齐博客:

8.简述触发器、函数、视图、存储过程?
‘触发器’:
对数据库某个表进行【增、删、改】前后,自定义的一些SQL操作
‘函数’:
在SQL语句中使用的函数 #例如:select sleep(2)
聚合函数:max、sam、min、avg
时间格式化:date_format
字符串拼接:concat
自定制函数:(触发函数通过 select)
‘视图’:
对某些表进行SQL查询,将结果实时显示出来(是虚拟表),只能查询不能更新
‘存储过程’:
将提前定义好的SQL语句保存到数据库中并命名;以后在代码中调用时直接通过名称即可
参数类型:in、out、inout

9.MySQL索引种类
单列
功能
普通索引:加速查找
唯一索引:加速查找 + 约束:不能重复(只能有一个空,不然就重复了)
主键(primay key):加速查找 + 约束:不能重复 + 不能为空
多列
  联合索引(多个列创建索引)-----> 相当于单列的普通索引
  联合唯一索引 -----> 相当于单列的唯一索引
  ps:联合索引的特点:遵循最左前缀的规则
其他词语:
·· - 索引合并,利用多个单例索引查询;(例如在数据库查用户名和密码,分别给用户名和密码建立索引)

  • 覆盖索引,在索引表中就能将想要的数据查询到;
    10.索引在什么情况下遵循最左前缀的规则?
    联合索引

11.主键和外键的区别?
‘主键’
唯一标识一条记录
用来保证数据的完整性
主键只能有一个
‘外键’
表的外键是另一个表的主键,外键可以有重复的,可以是空值
用来和其他表建立联系用的
一个表可以有多个外键
‘索引’
该字段没有重复值,但可以有一个空值
提高查询速度
一个表可以有多个唯一索引

12.MySQL常见的函数?

'当前时间'
    select now();
'时间格式化'
    select DATE_FORMAT(NOW(), '%Y(年)-%m(月)-%d(日) %H(时):%i(分):%s(秒)')
'日期加减'
    select DATE_ADD(DATE, INTERVAL expr unit)
    select DATE_ADD(NOW(), INTERVAL 1 DAY) #当前日期加一天
    \expr:正数(加)、负数(减)
    \unit:支持毫秒microsecond、秒second、小时hour、天day、周week、年year
'类型转换'
    cast( expr AS TYPE) 
    select CAST(123 AS CHAR)
'字符串拼接'
    concat(str1,str2,……)
    select concat('hello','2','world') --> hellow2world
'聚合函数'
    avg() #平均值
    count() #返回指定列/行的个数
    min() #最小值
    max() #最大值
    sum() #求和
    group_concat() #返回属于一组的列值,连接组合而成的结果
'数学函数'
    abs() #绝对值
    bin() #二进制
    rand() #随机数
13.列举 创建索引但是无法命中索引的8种情况。
#使用'like ‘%xx’'
    select * from tb1 where name like '%cn';
#使用'函数'
    select * from tb1 where reverse(name)='zgc';
#使用'or'
    select * from tb1 where nid=1 or  email='zgc@gmial.com';
    特别的:当or条件中有未建立索引的列才失效,一下会走索引
            # select * from tb1 where nid=1 or name='zgc';
            # select * from tb1 where nid=1 or email='zgc@gmial.com' and name='zgc';
#'类型不一致'
    如果列是字符串类型,传入条件是必须用引号引起来,不然则可能会无法命中
    select * from tb1 where name=666;
#含有'!= '
    select * from tb1 where name != 'zgc';
    特别的:如果是主键,还是会走索引
            # select * from tb1 where nid != 123;
#含有'>'
    select * from tb1 where name > 'zgc';
    特别的:如果是主键或者索引是整数类型,则还是会走索引
            # select * from tb1 where nid > 123;
            # select * from tb1 where name > 123;
#含有'order by'
    select email from tb1 order by name desc;
    当根据索引排序时,选择的映射如果不是索引,则不走索引
    特别的:如果对主键排序,则还是走索引:
            # select * from tb1 order by nid desc;

#组合索引最左前缀
    如果组合索引为:(name,email)
    name and email #使用索引
    name           #使用索引
    email          #不使用索引

14.如何开启慢日志查询?

修改配置文件

slow_query_log = OFF 是否开启慢日志记录
 long_query_time = 2 时间限制,超过此时间,则记录
 slow_query_log_file = /usr/slow.log 日志文件
 log_queries_not_using_indexes = OFF 为使用索引的搜索是否记录
 下面是开启
 slow_query_log = ON
 long_query_time = 2
 log_queries_not_using_indexes = OFF
 log_queries_not_using_indexes = ON
 注:查看当前配置信息:
    show variables like ‘%query%’
 修改当前配置:
     set global 变量名 = 值

15.数据库导入导出命令(结构+数据)?
#导出:
mysqldump --no-defaults -uroot -p 数据库名字 > 导出路径
‘–no-defaults’:解决“unknown option --no-beep”报错
#导入:
1、mysqldump -uroot -p 数据库名称 < 路径
2、进入数据库; source + 要导入数据库文件路径
导出现有数据库数据:(当有提示出入密码。-p就不用加密码)
mysqldump -u用户名 -p密码 数据库名称 >导出文件路径 # 结构+数据
mysqldump -u用户名 -p密码 -d 数据库名称 >导出文件 路径 # 结构
导入现有数据库数据:
mysqldump -uroot -p密码 数据库名称 < 文件路径

16.数据库优化方案?

1、创建数据表时把固定长度的放在前面
2、将固定数据放入内存:choice字段(django中用到,1,2,3对应相应内容)
3、char不可变,varchar可变
4、联合索引遵循最左前缀(从最左侧开始检索)
5、避免使用 select *
6、读写分离:
#利用数据库的主从分离:主,用于删除、修改、更新;从,用于查
#实现:两台服务器同步数据
\原生SQL:select * from db.tb
\ORM:model.User.object.all().using(‘default’)
\路由:db router
7、分库
# 当数据库中的表太多,将某些表分到不同数据库,例如:1W张表时
# 代价:连表查询跨数据库,代码变多
8、分表
# 水平分表:将某些列拆分到另一张表,例如:博客+博客详情
# 垂直分表:将某些历史信息,分到另外一张表中,例如:支付宝账单
9、加缓存
# 利用redis、memcache(常用数据放到缓存里,提高取数据速度)
# 缓存不够可能会造成雪崩现象
10、如果只想获取一条数据
select * from tb where name = ‘zgc’ limit 1;

17.char和varchar的区别?
#char类型:定长不可变
存入字符长度大于设置长度时报错;
存入字符串长度小于设置长度时,用空格填充以达到设置字符串长度;
简单粗暴,浪费空间,存取速度快。
#varchar类型:可变
存储数据真实内容,不使用空格填充;
会在真实数据前加1-2Bytes的前缀,用来表示真实数据的bytes字节数;
边长、精准、节省空间、存取速度慢。

18.简述MySQL的执行计划?
查看有没有命中索引,让数据库帮看看运行速度快不快
explain select * from table;
#explain + SQL语句
#SQL在数据库中执行时的表现情况,通常用于SQL性能分析,优化等场景。
‘explain select * from rbac_userinfo where id=1;’

19.在对name做了唯一索引前提下,简述以下区别:

select * from tb where name = ‘Oldboy-Wupeiqi’ 

    select * from tb where name = ‘Oldboy-Wupeiqi’ limit 1

是这样的的,用where条件过滤出符合条件的数据的同时,进行计数,
比如limit 1,那么在where过滤出第1条数据后,他就会直接把结果select出来返回给你,整个过程就结束了。没做唯一索引的话,前者查询会全表扫描,效率低些,limit 1,只要找到对应一条数据,就不继续往下扫描.
然而 name 字段添加唯一索引了,加不加limit 1,意义都不大;

20.1000w条数据,使用limit offset 分页时,为什么越往后翻越慢?如何解决?
#例如:
#limit 100000,20; 从第十万条开始往后取二十条,
#limit 20 offset 100000; limit后面是取20条数据,offset后面是从第10W条数据开始读
因为当一个数据库表过于庞大,LIMIT offset, length中的offset值过大,则SQL查询语句会非常缓慢

‘优化一’
先查看主键,再分页:
select * from tb where id in (select id from tb where limit 10 offset 30)

‘优化二’
记录当前页,数据、ID、最大值和最小值(用于where查询)
在翻页时,根据条件进行筛选,筛选完毕后,再根据 limit offset 查询
select * from(select * from tb where id > 2222) as B limit 10 offset 0;
\如果用户自己修改页码,也可能导致变慢,此时可以对 url 页码进行加密,例如rest framework

‘优化三’
可以按照当前业务需求,看是否可以设置只允许看前200页;
一般情况下,没人会咔咔看个几十上百页的;

21.什么是索引合并?
1、索引合并是把几个索引的范围扫描合并成一个索引。
2、索引合并的时候,会对索引进行并集,交集或者先交集再并集操作,以便合并成一个索引。
3、这些需要合并的索引只能是一个表的。不能对多表进行索引合并。

简单的说,索引合并,让一条sql可以使用多个索引。对这些索引取交集,并集,或者先取交集再取并集。
从而减少从数据表中取数据的次数,提高查询效率。
22.什么是覆盖索引?
#解释一:
  就是select的数据列只用从索引中就能够取得,不必从数据表中读取,换句话说查询列要被所使用的索引覆盖。
#解释二:
  索引是高效找到行的一个方法,当能通过检索索引就可以读取想要的数据,那就不需要再到数据表中读取行了。
  如果一个索引包含了(或覆盖了)满足查询语句中字段与条件的数据就叫做覆盖索引。
#注意:MySQL只能使用B-Tree索引做覆盖索引

23.简述数据库读写分离?
#利用数据库的主从分离:主,用于删除、修改、更新;从,用于查
#实现:两台服务器同步数据(减轻服务器的压力)
原生SQL: select * from db.tb
ORM:model.User.object.all().using(‘default’)
路由:db router
24.简述数据库分库分表?(水平、垂直)
#1、分库
当数据库中的表太多,将某些表分到不同数据库,例如:1W张表时
代价:连表查询跨数据库,代码变多
#2、分表
水平分表:将某些列拆分到另一张表,例如:博客+博客详情
垂直分表:将某些历史信息,分到另外一张表中,例如:支付宝账单
25.redis和memcached比较?
#1.存储容量:
memcached超过内存比例会抹掉前面的数据,而redis会存储在磁盘
#2.支持数据类型:
memcached只支持string;
redis支持更多;如:hash、list、集合、有序集合
#3.持久化:
redis支持数据持久化,可以将内存中的数据保持在磁盘中,memcached无
#4.主从:
即master-slave模式的数据备份(主从)。
#5.特性
Redis在很多方面具备数据库的特征,或者说就是一个数据库系统
Memcached只是简单的K/V缓存

26.redis中数据库默认是多少个db 及作用?
#redis默认有16个db,db0~db15(可以通过配置文件支持更多,无上限)
#并且每个数据库的数据是隔离的不能共享
#可以随时使用SELECT命令更换数据库:redis> SELECT 1
#注意:
多个数据库之间并不是完全隔离的
比如FLUSHALL命令可以清空一个Redis实例中所有数据库中的数据。

26.python操作redis的模块?
https://www.jianshu.com/p/2639549bedc8

- 连接
- 直接连接:
    import redis 
    r = redis.Redis(host='10.211.55.4', port=6379)
    r.set('foo', 'Bar')
    print r.get('foo')
- 连接池:
    import redis
    pool = redis.ConnectionPool(host='10.211.55.4', port=6379)
     
    r = redis.Redis(connection_pool=pool)
    r.set('foo', 'Bar')
    print r.get('foo')

27.如果redis中的某个列表中的数据量非常大,如何实现循环显示每一个值?
①# 通过scan_iter分片取,减少内存压力

scan_iter(match=None, count=None)增量式迭代获取redis里匹配的的值
#match,匹配指定key
#count,每次分片最少获取个数
    r = redis.Redis(connection_pool=pool)
    for key in r.scan_iter(match='PREFIX_*', count=100000):
        print(key)

②- 如果一个列表在redis中保存了10w个值,我需要将所有值全部循环并显示,请问如何实现?
一个一个取值,列表没有iter方法,但能自定义

def list_scan_iter(name,count=3):
    start = 0
    while True:
        result = conn.lrange(name, start, start+count-1)
        start += count
        if not result:
            break
        for item in result:
            yield item
    for val in list_scan_iter('num_list'):
        print(val)
        场景:投票系统,script-redis

28.redis如何实现主从复制?以及数据同步机制?
#实现主从复制
‘创建6379和6380配置文件’
redis.conf:6379为默认配置文件,作为Master服务配置;
redis_6380.conf:6380为同步配置,作为Slave服务配置;
‘配置slaveof同步指令’
在Slave对应的conf配置文件中,添加以下内容:
slaveof 127.0.0.1 6379
#数据同步步骤:
(1)Slave服务器连接到Master服务器.
(2)Slave服务器发送同步(SYCN)命令.
(3)Master服务器备份数据库到文件.
(4)Master服务器把备份文件传输给Slave服务器.
(5)Slave服务器把备份文件数据导入到数据库中.

29.redis中的sentinel的作用?
帮助我们自动在主从之间进行切换
检测主从中 主是否挂掉,且超过一半的sentinel检测到挂了之后才进行进行切换。
如果主修复好了,再次启动时候,会变成从。
启动主redis:
redis-server /etc/redis-6379.conf 启动主redis
redis-server /etc/redis-6380.conf 启动从redis
在linux中:
找到 /etc/redis-sentinel-8001.conf 配置文件,在内部:
- 哨兵的端口 port = 8001
- 主redis的IP,哨兵个数的一半/1
找到 /etc/redis-sentinel-8002.conf 配置文件,在内部:
- 哨兵的端口 port = 8002
- 主redis的IP, 1
启动两个哨兵

30.如何实现redis集群?
#基于【分片】来完成。
- 集群是将你的数据拆分到多个Redis实例的过程
- 可以使用很多电脑的内存总和来支持更大的数据库。
- 没有分片,你就被局限于单机能支持的内存容量。
#redis将所有能放置数据的地方创建了 16384 个哈希槽。
#如果设置集群的话,就可以为每个实例分配哈希槽:
- 192.168.1.20【0-5000】
- 192.168.1.21【5001-10000】
- 192.168.1.22【10001-16384】
#以后想要在redis中写值时:set k1 123
- 将k1通过crc16的算法转换成一个数字,然后再将该数字和16384求余,
- 如果得到的余数 3000,那么就将该值写入到 192.168.1.20 实例中。
#集群方案:
- redis cluster:官方提供的集群方案。
- codis:豌豆荚技术团队。
- tweproxy:Twiter技术团队。
31.redis中默认有多少个哈希槽?
#redis中默认有 16384 个哈希槽。
32.简述redis的有哪几种持久化策略及比较?
#RDB:每隔一段时间对redis进行一次持久化。
- 缺点:数据不完整
- 优点:速度快
#AOF:把所有命令保存起来,如果想重新生成到redis,那么就要把命令重新执行一次。
- 缺点:速度慢,文件比较大
- 优点:数据完整
-
33.列举redis支持的过期策略。
#数据集(server.db[i].expires)

a、voltile-lru: #从已设置过期时间的数据集中,挑选最近频率最少数据淘汰
b、volatile-ttl: #从已设置过期时间的数据集中,挑选将要过期的数据淘汰
c、volatile-random:#从已设置过期时间的数据集中,任意选择数据淘汰
d、allkeys-lru: #从数据集中,挑选最近最少使用的数据淘汰
e、allkeys-random: #从数据集中,任意选择数据淘汰
f、no-enviction(驱逐):#禁止驱逐数据

34.MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中都是热点数据?
相关知识:redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略(回收策略)。redis 提供 6种数据淘汰策略:

volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
no-enviction(驱逐):禁止驱逐数据

36.如何基于redis实现消息队列?
#通过发布订阅模式的PUB、SUB实现消息队列
#发布者发布消息到频道了,频道就是一个消息队列。
#发布者:

import redis
conn = redis.Redis(host='127.0.0.1',port=6379)
conn.publish('104.9MH', "hahahahahaha")

#订阅者:

import redis
conn = redis.Redis(host='127.0.0.1',port=6379)
pub = conn.pubsub()
pub.subscribe('104.9MH')
while True:
    msg= pub.parse_response()
    print(msg)

对了,redis 做消息队列不合适
业务上避免过度复用一个redis,用它做缓存、做计算,还做任务队列,压力太大,不好。

37.如何基于redis实现发布和订阅?以及发布订阅和消息队列的区别?
#发布和订阅,只要有任务就所有订阅者每人一份。

发布者: #发布一次
    import redis
    conn = redis.Redis(host='127.0.0.1',port=6379)
    conn.publish('104.9MH', "hahahahahaha")
订阅者: #'while True'一直在接收
    import redis
    conn = redis.Redis(host='127.0.0.1',port=6379)
    pub = conn.pubsub()
    pub.subscribe('104.9MH')
    while True:
        msg= pub.parse_response()
        print(msg)

38.什么是codis及作用?
Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说,
连接到 Codis-Proxy(redis代理服务)和连接原生的 Redis-Server 没有明显的区别,
上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作,
所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务.

39.什么是twemproxy及作用?
#什么是Twemproxy
是Twtter开源的一个 Redis 和 Memcache 代理服务器,
主要用于管理 Redis 和 Memcached 集群,减少与Cache服务器直接连接的数量。
他的后端是多台REDIS或memcached所以也可以被称为分布式中间件。

#作用
通过代理的方式减少缓存服务器的连接数。
自动在多台缓存服务器间共享数据。
通过配置的方式禁用失败的结点。
运行在多个实例上,客户端可以连接到首个可用的代理服务器。
支持请求的流式与批处理,因而能够降低来回的消耗。

40.写代码实现redis事务操作。

import redis
pool = redis.ConnectionPool(host='10.211.55.4', port=6379)
conn = redis.Redis(connection_pool=pool)
#pipe = r.pipeline(transaction=False)
pipe = conn.pipeline(transaction=True)
#开始事务
pipe.multi()
pipe.set('name', 'zgc')
pipe.set('role', 'haha')
pipe.lpush('roless', 'haha')
#提交
pipe.execute()
'注意':咨询是否当前分布式redis是否支持事务

41.redis中的watch的命令的作用?
#用于监视一个或多个key
#如果在事务执行之前这个/些key被其他命令改动,那么事务将被打断

42.基于redis如何实现商城商品数量计数器?

'通过redis的watch实现'
import redis
conn = redis.Redis(host='127.0.0.1',port=6379)
#conn.set('count',1000)
val = conn.get('count')
print(val)
with conn.pipeline(transaction=True) as pipe:
    # 先监视,自己的值没有被修改过
    conn.watch('count')
    # 事务开始
    pipe.multi()
    old_count = conn.get('count')
    count = int(old_count)
    print('现在剩余的商品有:%s',count)
    input("问媳妇让不让买?")
    pipe.set('count', count - 1)
    # 执行,把所有命令一次性推送过去
    pipe.execute()
数据库的锁

43.简述redis分布式锁和redlock的实现机制。44.什么是一致性哈希?Python中是否有相应模块?
#一致性哈希一致性hash算法(DHT)可以通过减少影响范围的方式,解决增减服务器导致的数据散列问题,从而解决了分布式环境下负载均衡问题;
如果存在热点数据,可以通过增添节点的方式,对热点区间进行划分,将压力分配至其他服务器,重新达到负载均衡的状态。# 模块:hash_ring
Python模块–hash_ring,即Python中的一致性hash

45.如何高效的找到redis中所有以oldboy开头的key?
redis 有一个keys命令。
#语法:KEYS pattern
#说明:返回与指定模式相匹配的所用的keys。
该命令所支持的匹配模式如下:
1、?:用于匹配单个字符。例如,h?llo可以匹配hello、hallo和hxllo等;
2、:用于匹配零个或者多个字符。例如,hllo可以匹配hllo和heeeello等;
2、[]:可以用来指定模式的选择区间。例如h[ae]llo可以匹配hello和hallo,但是不能匹配hillo。同时,可以使用“/”符号来转义特殊的字符
#注意
KEYS 的速度非常快,但如果数据太大,内存可能会崩掉,
如果需要从一个数据集中查找特定的key,最好还是用Redis的集合结构(set)来代替。