RedisMySQLMongoDB相关面试题整理
Posted yazhou-lai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RedisMySQLMongoDB相关面试题整理相关的知识,希望对你有一定的参考价值。
第三部分 数据库和缓存(46题)
1. 列举常见的关系型数据库和非关系型都有那些?
关系型数据库:通过外键关联来建立表与表之间的关系
非关系型数据库:以对象的形式存储在数据库中,而对象之间的关系是通过对象自身的属性决定
关系型数据库:mysql、SQLite、Oracle
优点:使用方便:通用的sql语言操作,易于维护
非关系型数据库:Redis、MongoDB
优点:读写性能很高,基于键值对存储,数据没有耦合性,容易扩展
2. MySQL常见数据库引擎及比较?
如何修改数据库引擎:
方式一:修改my.ini文件,在最后一行追加default-storage-engine=InnoDB,然后重启服务
方式二:在创建表的时候指定
create table mytbl(
id int primary key,
name verchar(50)
)type=MyISAM
InnoDB:支持事务,支持外键,支持行锁,mysql5.5后InnoDB是默认的引擎
InnoDB适合频繁修改以及涉及到安全性较高的应用
优点:支持事务,支持外键,并发量较大,适合大量update。
缺点:查询数据相对较快,不适合大量的select。
MyISAM:不支持事务,不支持外键,优势是访问速度快。
对事务完整性没有要求或者以select,insert为主的应用基本上可以用这个引擎来创建表
MYISAM的性能更优,占用的存储空间少
优点:查询数据相对较快,适合大量的select,可以全文索引。
缺点:不支持事务,不支持外键,并发量较小,不适合大量update
Memory:Memory存储引擎使用存在于内存中的内容来创建表。每个memory表只实际对应一个磁盘文件,
MEMORY类型的表访问非常得快,因为它的数据是放在内存中的,并且默认使用HASH索引。
但是一旦服务关闭,表中的数据就会丢失掉
Blackhole:任何写入到此引擎的数据均会被丢弃掉, 不做实际存储;Select语句的内容永远是空。
充当日志服务器
Merge: Merge引擎允许将一组使用MyISAM存储引擎的并且表结构相同的(字段顺序,字段名称,字段类型,索引定义顺序)的数据
表合并成为一个表,方便数据查询
3. 简述数据三大范式?
什么是范式:数据库设计对数据的存储性能,还有开发人员对数据的操作都有莫大的关系。所以建立科学的,规范的的数据库是需要满足一些规范的来优化数据数据
存储方式。
实体:表
属性:表中的字段
关系:表与表之间的关系
第一范式(1NF):数据表的每一列(每个字段)必须是不可拆分的最小单元,也就是确保每一列的原子性;
第二范式(2NF):满足1NF后,要求表中的所有列,都必须依赖于主键,而不能有任何一列与主键没有关系,也就是说一个表只描述
一件事情:例如订单表只描述订单相关信息,所以每个字段都必须与订单id相关。
第三范式(3NF):必须先满足2NF,要求:表中的每一列只与主键直接相关而不是间接相关。
例如:订单表中需要客户信息,在分离出客户表后,订单表只需要一个客户id即可,而不能有其他客户信息。
数据库的五大约束:
1.primary key :主键默认非空,只有主键才能设置自增,自增一定是主键,主键不一定自增
2.unique :设置唯一性约束,不能有重复值;unique(ip,port) 联合唯一, unique(id)
3.default
4.not null :设置非空约束,该字段不能为空;
5.foreign key : 只有innodb支持外键 constraint 外键名 foreign key(外键字段) references 参照表(参照字段) on delete cascade on update cascade # 同步更新同步删除
6.auto_increment: 标识该字段的值自动增长(整数类型,而且为主键)
ps:unique + nut null == primary key
unique 唯一的,可以为空
primary key:唯一的,不可以为空
4. 什么是事务?MySQL如何支持事务?
事务:事务用于将某些操作的多个sql语句作为原子性操作,一旦某个出现错误,即可回滚到原来状态,从而保证数据库的完整性。
MySQL中只有使用了InnoDB的数据库或表才支持事务
5. 简述数据库设计中一对多和多对多的应用场景?
一对多:学生与班级------一个学生只能属于一个班级,一个班级有多个学生
多对多:学生和课程------一个学生可以选择多门课程,一个课程可以被多个学生选
一对一:学生与学号------一个学生有一个学号,一个学号只属于一个学生
5.1 pymysql的使用?
import pymysql
# 连接
conn = pymysql.connect(host=‘127.0.0.1‘,port=3306,user=‘root‘,password=‘‘,db=‘db1‘,charset=‘utf8‘)
# 创建游标
cursor = conn.cursor()
sql = "select * from userinfo where username=‘%s‘ and pwd=‘%s‘" %(user,pwd) #%s加引号
# 执行sql语句
result = cursor.execute(sql) # 执行SQL语句,返回的是受影响的行数
print(result)
# 关闭游标,关闭连接
cursor.close()
conn.colse()
# execute() 之sql注入:
# 1,用户名存在,绕过密码,在输入用户名的时候:yazhou‘ -- asfsfsdfsdfds
在一条sql语句中如果遇到 select * from userinfo where username=‘yazhou‘ -- asfsfsdfsdfds‘ and pwd=‘‘
则--之后的条件被注释掉了(注意--后面有一个空格)
# 2。用户不存在,绕过用户名和密码,在输入用户名的时候:dfdsf‘ or 1=1 -- (注意--后有一个空格)
select * from userinfo where username=‘dfdsf‘ or 1=1 -- ‘ and pwd=‘‘
# 解决办法
原来我们是对sql进行字符串的拼接,现在我们改写为:
sql = ‘select * from userinfo where name=%s and password=%s‘ #%s不加引号
result = cursor.execute(sql,[user,pwd]) #pymsql模块自动帮我们解决sql注入问题
# 增删改:conn.commit()
在数据库里增删改的时候,必须要进行提交,否则不生效
# 获取数据
fetchone():获取下一行数据
fetchall():获取所有数据
fetchmany():获取多少行数据,fetchmany(4) 4行
cursor.execute(sql,[user,pwd])
cursor.fetchall()
以上都是元组返回,只能看到每行的数据,却不知道每列代表什么,这是时候我们就可以用返回字典的方式:
cursor = conn.cursor(cursor=pymysql.cursors.DicCursor) #在实例化的时候,将属性cursor设置为pymysql.cursors.DictCursor
cursor.execute(sql,[user,pwd])
rows = cursor.fetchmany(2)
print(rows) # [{‘id‘: 1, ‘username‘: ‘mjj‘, ‘pwd‘: ‘123‘}, {‘id‘: 3, ‘username‘: ‘张三‘, ‘pwd‘: ‘110‘}]
6. 如何基于数据库实现商城商品计数器?
create table product(
id int primary key anto_incremtn,
pname varchar(64),
pcount int);
7. 常见SQL(必备)
# 库的操作
create database db1 charset utf8; # 创建数据库并指定编码,默认utf-8
show create database db1; # 查看创建的数据库
show databases; # 查看所有的数据库
use db1; # 使用db1数据库
select databases(); # 查看当前所在的数据库
alter database db1 charset gbk; # 修改数据库编码
drop database db1; # 删除数据库db1
# 表的操作
# 增
create table t1(id int,name char(20)); # 创建t1表
# 删
drop table t1; # 删除表
# 改
alter table t1 modify name char(6); # 修改表字段的属性
alter table t1 change name NAME char(7); # 修改表字段
# 查
show create table t1; # 查看创建的t1表
show tables; # 查看当前库下所有的表
desc t1; # 查看t1表的详细信息
# 记录的操作
# 增
insert t1(id,name) values(1,‘aaa‘),(2,‘bbb‘); #给t1表插入多条记录
insert t1 values(3,‘ccc‘); # 插入一条记录(不写表字段,则必须全部字段对应值)
insert t1(id) values(‘4‘); # 只插入id,name默认为Null
# 删
delete from t1; # 清空表中的记录,再插入,自增id从删除前最大id开始
truncate table t1; # 自增id从0开始
delete from t1 where id =2; # 删除id=2的记录
# 改
update t1 set name=‘ddd‘ where id=2; # 将id=2的name改为ddd
# 查
select id from t1; # 值查看id
select * from t1; # 查看所有字段
8. 简述触发器、函数、视图、存储过程?
触发器:定制用户对表进行增删改操作时的前后行为,没有查询
基本语法插入前:create trigger tri_before_insert_tb1 before insert on tb1 for each row
begin
end
# 对用户表的after insert后记录一条日志,到userLog表中,用户表affirm enum(‘yes‘,‘no‘) 表示插入成功是否
eg: delimiter // # 修改定界符为//,默认为;
create trigger after_user_insert after insert on user_tb for each row # 触发器的名字为:after_user_insert,对user_tb表的
begin
if new.affirm = ‘yes‘ then # 插入的时候用new对象,(对象可以直接取插入的值),更新删除的时候用old
insert into userLog(u_name,u_reg_time) values(new.name,new.reg_time);
end // # 触发器结束
delimiter; # 再将定界符修改回来
# 查看触发器
select * from information_schema.TRIGGERG;
函数:mysql中提供了许多内置函数
1.round(x,y)
2.rand() # 返回0-1直接的随机数,floor(rand()*1000) 生产0-1000直接的整数
3.聚合函数
avg(col) 指定列的平均值
count(col) 指定列中非Null的个数
min(col) 指定列中最小值
max(col)
sum(col)指定列的所有值和
4.字符串函数 char_length(str),
5.日期函数
slect now() # 年月日时分秒
select curdata() # 年与日
select curtime() # 时分秒
6.格式化
selectdate_format(‘2009-10-11 22:23:11‘,‘str‘)
7.MD5()
8.声明一个变量
set @variable_name = what;
其中what可以是基本数据类型,也可以是select的语句结果
eg:
set @A = select sub_time from blog where id = 1;
select @A;
视图:通俗的讲,视图就是一条select语句执行后返回的结果集。是一种虚拟存在的表,逻辑表,本身不包含数据。
create view view_name as SQL语句
多次用同一个虚拟表做为子查询的时候,我们可以将其创建一个视图,用以后用
# 创建使用视图
select cname from course where teacher_id = (select tid from teacher where tname=‘李老师‘);
create view teacher_view as select tid from teacher where tname=‘李老师‘;
select cname from course where teacher_id=(select tid from teacher_view);
# 修改视图的语句
alter view teacher_view as select * from course where cid>3;
# 删除视图
drop view teacher_view;
# 查看视图
select * from information_schema.VIEWS
存储过程:是存储在数据库目录中的一些声明性语句。java,python等可以调用存储过程。
优点:
1.存储过程有助于提高应用程序的性能,存储过程被编译后,mysql将其放入缓存
2.减少与应用程序之间的流量,因为应用程序不必发送冗长的sql语句,只发存储过程的名字和参数接即可
3.存储过程对应用程序可重用,透明。将数据库接口暴露给应用程序
4.存储过程是安全的。数据库管理员向应用程序授予适当的权限
缺点:
1.大量使用存储过程,使用这些存储过程的每个连接的内存使用量大大增加
2.很难调试存储过程
3.开发和维护存储过程不容易。
#创建一个存储过程:
delimiter //
create procedure b1() # 存储过程的名字为b1
begin
select * from blog; # 存储过程的主体,
end //
delimiter ;
存储过程的调用:call b1();
在python中调用:cursor.callproc(‘b1‘)
print(cursor.fetchall())
#查看存储过程:show create procedure b1;
eg: # 存储过程传参
delimiter //
create procedure b2(in n int) # 需要传一个n为int的参数
begin
select * from blog where id=n;
end //
delimiter ;
# 调用
cursor.callproc(‘b2‘,(3))
事务:事务用于将某些操作的多个sql作为原子性操作,一旦某个出现错误,即可回滚到原来状态,从而保证数据的完整性
关系型数据库事务必须满足是个条件/特征:
数据库系统必须维护事务的以下特性(简称ACID):
原子性(Atomicity)
一致性(Consistency)
隔离性(Isolation)
持久性(Durability)
原子性:一个事务中的所有操作,要么全部完成,要么全部不完成
一致性:事务前后,数据库完整性没有被破坏
隔离性:数据库中允许多个并发事务同时对数据进行读取修改,隔离性防止多个事务交叉执行导致数据不一致
持久性:事务处理后,对数据修改是永久的。
begin或 start transaction ,开启一个事务
commit 或commit work,提交事务,并对数据库永久修改
rollback或rollback work,回滚会结束用户的事务,并撤销正在进行的所有未提交的修改
eg:
begin;
insert into tb value(5);
insert into tb value(6);
commit;
start transaction;
insert into tb value(5);
insert into tb value(6);
rollback;
9. MySQL索引种类
#什么是索引:
数据库中专门帮助用户快速查找数据的一种数据结构,类似于字典中的目录(查找字典内容的时候可以根据目录查找数据的位置,
然后直接获取)
#索引的作用:
约束和加速查找
#有无索引的区别:
无索引:从前往后一条一条查找
有索引:创建索引的本质,就是创建额外的文件(查询的时候,先去额外的文件中定位置,然后再去原始表中查询,但是创建索引越多,
会对硬盘有所损耗,创建索引后必须命中索引才能有效,查询快,但是更新删除插入依旧慢
#MySQL中的索引的存储类型有两种:
BTREE:innoDB默认支持,btree是根据二分查找的
HASH:查询单条很快(比btree都快),但是范围模糊查询不一定快,因为hash值是无序的
#索引的缺点:
创建和维护索引需要时间,随着数量的增多锁耗时也变多
索引占用空间,大量的索引,索引文件可能比数据文件更快达到上限值
当对表中的数据进行修改的时候,索引也要动态维护
#使用原则:
对经常更新的表避免使用过多的索引,对经常查询的表应创建索引
数据量小的表最好不要建立索引
在一同值多的列上(字段上)不要建立索引,比如学生表的性别,相反在同值少的字段上可建立索引
# 索引的分类
单列索引:
普通索引:MySQL中基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值,纯粹为了查询数据更快一点
仅有一个作用:加速查找。
# 方法一 在创建表的时候,创建索引
create table userinfo(
nid int not null auto_increment primary key,
name varchar(32) not null,
emial varchar(64) not null,
index ix_name(name));
# 方法二 在创建表后用create创建索引
create index ix_name on userinfo(name); # create index 索引的名字 on 表名(列名)
# 删除索引
drop index ix_name on userinfo; # drop index 索引的名字 on 表名
# 查看索引
show index from userinfo; # show index from 表名
唯一索引:索引列中的值必须是唯一的,但是允许为空值,
作用:加速查找和唯一约束(可含Null),
# 方法一 在创建表的时候,创建索引
create table userinfo(
id int not null auto_increment primary key,
name varchar(32) not null,
unique index ix_name(name));
# 方法二 在创建表后用create创建索引
create unique index ix_name on userinfo(name); # create unique index 索引名 on 表名(列名)
# 删除唯一索引
drop unique index ix_name on userinfo; # drop index 索引的名字 on 表名
主键索引:是一种特殊的唯一索引,不允许有空值。
作用:加速查找和唯一约束(不含null)
# 方法一 在创建表的时候,创建索引
create table userinfo(
id int not null auto_increment primary key,
name varchar(32) not null,
unique index ix_name(name));
# 方法二 在创建表后用create创建索引
create unique index ix_name on userinfo(name); # create unique index 索引名 on 表名(列名)
# 删除唯一索引
drop unique index ix_name on userinfo; # drop index 索引的名字 on 表名
联合索引:
联合主键索引:
create index name_email on userinfo(name,email); # 最左前缀顺序为创建的顺,name,email
# 组合索引最左前缀为name,在单列查询中的条件是最左前缀name,那么才使用索引,速度快,否则不使用索引
eg:select * from userinfo email=‘[email protected]‘; # 不使用索引,
select * from userinfo name=‘heihei‘; # 使用索引
# 但是在使用组合索引的多列查询,不管顺序,都是使用索引查询,速度快
联合唯一索引
联合普通索引:
全文索引:只有在MyISAM引擎上才能使用,只能在char,varchar,text类型字段上使用全文索引
空间索引:
索引(A,B)
A 走索引,
B 不走索引
A,B 走索引
B,A 走索引
C,A 走索引
C,B 不走索引
索引注意事项:
1.避免使用select *
2.count(1),count(col) 代替 count(*)
3.创建表的时候尽量用char代替varchar
4.组合索引,代替多个单列索引
5.使用join来代替子查询
执行计划:
explain + sql语句:用来显示sql执行的信息参数,根据信息可以做优化
10. 索引在什么情况下遵循最左前缀的规则?
在使用组合索引的情况下,小遵循最左前缀规则:
最左前缀匹配规则:mysql会一直向右匹配知道遇到范围查询(<,>,between,like)等就停止匹配。
例如:a = 1 and b =2 and c > 3 and d = 4,如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果
建立(a,b,d,c)的索引,那么都可以用到,
11. 主键和外键的区别?
#主键
定义:唯一标识一条记录,不能有重复的,不允许为空
作用:用来保证数据完整性
个数:主键只能有一个
#外键
定义:表的外键是另一表的主键, 外键可以有重复的, 可以是空值
作用:用来和其他表建立联系用的
个数:一个表可以有多个外键
12. MySQL常见的函数?
#聚合函数:
AVG(col)返回指定列的平均值
COUNT(col)返回指定列中非NULL值的个数
MIN(col)返回指定列的最小值
MAX(col)返回指定列的最大值
SUM(col)返回指定列的所有值之和
now() #返回当前时间
data_format(data,format) # 格式化
13. 列举 创建索引但是无法命中索引的8种情况。
1.如果条件中有or,即使其中有条件带索引,也不会使用(这也就是为什么少用or的原因)
注意:要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引
2.对于多列索引,不是使用的第一个,则不会生效
3.link查询以%开头,(以%结尾的:索引可以使用)
4.如果类型是字符串,那一定要在条件中将数据用引号引用起来。
5.如果mysql估计使用全表扫描要比使用索引快,则不使用索引
6.对小表查询
7.单独引用联合索引里的非第一位置的索引列
8.提示不使用索引
14. 如何开启慢日志查询?
开启慢日志查询,可以让mysql记录下查询超过指定时间的语句,通过定位分析性能瓶颈,才能更好的优化数据库。
# 查看是否开启慢日志
show variables like ‘slow_query%‘;
slow_query_log # 慢日志开启状态,OFF为未开启,ON为开启
slow_query_log_file # 慢日志的存放位置
# 查看慢日志超时时间
show variables like ‘long%‘;
long_query_time # 默认10秒,查询超过多少秒才记录
# 开启慢日志(方式一)
set global slow_query_log=1;
# 再次查看
show varibales like ‘slow_query_log%‘;
# 开启慢日志(推荐方法)
在my.conf文件中找到[mysqld],在其下面添加:
slow_query_log=1
slow_query_log_file=‘目录‘
long_query_time=1
15. 数据库导入导出命令(结构+数据)?
mysqldump -u root mytest > mytest.sql -p # 数据表结构+数据
mysqldump -u root -d mytest > mytest.sql -p #数据表结构
导入:
1.创建一个新数据库
create database test_db;
2.将备份的文件导入到test_db数据库中
mysql -u root test_db < mytest.sql -p
2.1 在mysql的库中导入
source mytest.sql
16. 数据库优化方案?
1.避免使用全表扫描,首先应考虑在where及order by涉及的col上建立索引
2.尽量避免在where字句中对字段进行null判断,否则导致引擎放弃使用索引,而进行全表扫描
最好也不要给数据库留NULL,竟可能使用Not null
3.很多时候用exists代替in是一个好的选择
4.索引并不是越多越好
5.使用join来代替子查询
6.使用事务
7.使用外键
8.使用索引
9.优化查询语句
17. char和varchar的区别?
1.数字
整数:int(n), 4字节32位,int类型后面的存储是显示宽度,而不是存储宽度
为int指定宽度,仅仅是查询结果的显示宽度,与存储范围无关
小数:
float(M,D):M是整数部分总个数,D是小数点后个数,M最大值为255,D最大值为30
double(M,D):M是整数部分总个数,D是小数点后个数。M最大值为255,D最大值为30
decimal(M,D):M是整数部分总个数(负号不算),D是小数点后个数。 M最大值为65,D最大值为30。
create table t5(x float(255,30); # D和M不能超过最大值
create table t6(x double(255,30); # D和M不能超过最大值
create table t7(x decimal(65,30); # D和M不能超过最大值
insert into tx values(1.1111111111111111111111111111111); # 同样给t5,t6,t7出入相同的数据,t7的精确度最高
2.字符串
char(10):简单粗暴,浪费空间,存取速度快,范围0-255
指定长度为10,存> 10的报错,存<10个字符的则用空格填充(右填充)直到10个字符存储
但是在查询的时候,会删除尾部的空格,不会显示填充的空格
varchar(10):变长,精准,节省空间,存取速度慢,范围0-65535
存储数据的真实内容,不会用空格填充,例如‘ab ‘,尾部的空格也会被存起来
强调:varchar类型会在真实数据前加1-2bytes的前缀,该前缀用来表示真实数据的bytes字节数。
真实数据<255bytes,则需要1bytes
真实数据>255bytes,则需要2bytes
char的存储方式是:对英文字符(ASCII)占用1个字节,对一个汉字占用两个字节;
varchar的存储方式是:对每个英文字符占用2个字节,汉字也占用2个字节。
text:用于保存变长的大字符串,65535
3.时间类型
data :YYYY-MM-DD
time :HH:MM:SS
year :YYYY
datetime(常用):YYYY-MM-DD HH:MM:SS 1001-9999 存储空间为4字节
create table t9(d date,t time,dt datetime);
insert into t9 values(now(),now(),now()); # mysql 自带now函数
注意:
单独插入时间时,需要以字符串形式,插入
插入年份时候,尽量使用4位值
插入两位年份时,<=69,以20开头,比如50,结果是2050
>=70,以19开头,比如71,结果1971
date_format()函数用于以不同的格式显示日期时间数据:
data是合法的日期,format是规格时间的格式
data_format(now(),‘%Y-%m-%d %H:%i:%s‘)
4.枚举和集合类型:
枚举:sex enum(‘male‘,‘female‘,‘other‘) #在指定范围内,多选一
集合:favorite set(‘play‘,‘music‘,‘read‘,‘study‘) #在指定范围内,多选多
18. 简述MySQL的执行计划?
执行计划:explain + sql语句
id select_type table type possible_keys key key_len ref rows extra
参数说明:
id:
id相同:执行顺序由上至下
id不同:如果是子查询,id的序号是递增的,id值越大优先级越高,越先被执行
id相同又不同:id相同,认为是一组,从上到下执行,id越大越先被执行
select_type:查询类型
simple 简单查询,查询中不含子查询或union
primary 最外层开始查询,查询总包含了任何复杂的子部分
subquery:在select或where中含有子查询
derived:
union 联合
table:正在访问的表名
type:SQL查询优化中一个很重要的指标,结果从好到坏
system >const>eq_ref>ref>index_merge>range>index>all
一般来说好的sql查询要达到range以上,最好能达到ref
syetem:系统表中只有一行,特例,忽略
const:通过索引一次就找到了,
possible_keys:可能使用的索引
key:真实使用的
key_len:索引字节长度
ref:显示索引的那一列被使用了
rows:估计为了找到所需的行而要读取的行
extra:不适合在其他字段中显示,但是十分重要的额外信息
19. 在对name做了唯一索引前提下,简述以下区别:
select * from tb where name = ‘Oldboy-Wupeiqi’
select * from tb where name = ‘Oldboy-Wupeiqi’ limit 1
区别是:第一条需要遍历整个数据表,而第二条找到一个就返回
20. 1000w条数据,使用limit offset 分页时,为什么越往后翻越慢?如何解决?
select * from userinfo limit 0,10;
select * from userinfo limit 10,10;
select * from userinfo limit 20,10;
……
select * from userinfo limit 1000w,10;
越往后,需要的时间就越长。是因为越往后查,全文扫描查询,回去数据库表中扫描数据。
limit10000,20的意思扫描满足条件的10020行,扔掉前面的10000行,返回最后的20行,问题就在这里。
优化方案:
情况1:只有上一页和下一页的情况
# 下一页,当前页最大id是299980,最小id是299971
select * from userinfo where id> max_id limit 10;
# 下一页,当前页最大id是299980,最小id是299971
select * from userinfo where id <min_id order by id desc limit 10;
select * from (select * from where id<min_id order by id desc limit 10) as A order by id asc;
情况二:有中间页面的情况
select * from userinfo where id in(
select id from (select * from userinfo where id > pre_max_id limit (cur_max_id-pre_max_id)*10) as A order by A.id desc limit 10
);
21. 什么是索引合并?
MySQL5.0之前,一个表一次只能使用一个索引,无法同时使用多个索引分别进行条件扫描。但是从5.1开始,
引入了 index merge 优化技术,对同一个表可以使用多个索引分别进行条件扫描。
eg:
SELECT * FROM tbl_name WHERE key1 = 10 OR key2 = 20;
SELECT * FROM tbl_name WHERE (key1 = 10 OR key2 = 20) AND non_key=30;
索引合并:对多个索引分别进行条件扫描,然后将它们各自的结果进行合并
1.是把几个索引的范围扫描合并成一个索引
2.索引合并的时候,会对索引进行并集,交集,以便合并成一个索引
3.需要合并的索引只能是一个表的,不能对多表进行索引合并
怎么确认使用了索引合并:
explain + sql:会在输出的type中显示index_merge,key列显示所使用过的索引
22. 什么是覆盖索引?
覆盖索引:覆盖索引是select的数据列只用从索引中就能够取得,不必读取数据行,换句话说查询列要被所建的索引覆盖。
举一个简单的例子:
create index index_name on tb_user(name); # 对表name字段建立索引
select count(name) from tb_user; # 查询name字段,就是覆盖索引了
# 因为select的数据列只从索引中就能取得,不必进行读取数据行。
explain select count(name) from tb_user; # 执行计划中可以看到Extra:Using index 就表示在使用索引覆盖
23. 简述数据库读写分离?
读写分离:
让主数据库处理事务性查询,而从数据库处理select查询
好处:增加冗余,增加了机器的处理能力,对于读操作为主的数据库,使用读写分离是最好的场景
读写分离高性能的原因:
1.物理服务器增加,负荷增加
2.主从只负责各自的写和读操作,
3.从库可以配置为MyISAM引擎,提升查询性能
24. 简述数据库分库分表?(水平、垂直)
关系型数据库比较容易成为系统的瓶颈,当表达到1000W或100G后,即使进行优化,很多操作蚁人性能底下。
此时就要考虑数据库切分了。切分的目的是减少数据库负担,缩短查询时间。
数据库分布式核心内容无非就是数据切分,以及切分后对数据的定位,整合。
数据切分就是将数据分散存储到多个数据库中,使得单一的数据库中的数据量变小,通过扩充主机的数量缓解
单一数据库的性能问题,而达到提升数据库操作性能的目的。
数据库切分根据切分类型:分为垂直(纵向)和水平(横向)切分
垂直切分:常见有垂直分库,垂直分表两种。
垂直分库:根据业务的耦合度,将关联度低的不同表存储在不同的数据库中。
垂直分表:是基于数据库中的列,某个表的字段比较多,可以新建一张扩张表,将经常不用的字段或者字段长度达的字段拆分出去。
水平切分:当一个应用难以在细粒度垂直切分的时候,或切分后数据量行数巨大等。
库内分表:
分库分表:是根据表内数据内在的逻辑关系,将同一张表按不同的条件分散到多个数据库或多个表中。每张表
只包含一部分数据,从而使得单个表的数据量变小,到达分布的效果。
25. redis和memcached比较?什么是redis?
redis具有丰富的数据类型,memcached只有简单的字符串
redis不仅仅支持简单的k/v类型数据,同时还提供list,set,hash等数据结构的存储,
redis支持数据备份,redis支持数据的持久化,可以将内存中的数据保存到磁盘中,重启的时候再次加载使用
memcachd挂掉后,数据不可恢复,redis挂掉后可以通aof恢复
memcached支持多线程,redis单线程操作。
redis的查询速度比memchached快的多
redis是一个基于内存的高性能k-v数据库,Remote Dictionary Server(远程字典服务)
26. redis中数据库默认是多少个db 及作用?
redis下,数据库是由一个整数索引标识,而不是由一个数据库名称
数据库的数量是可以配置的,默认情况下是16个(0-15)。修改/etc/redis/redis.conf下的databases = 16,指令:databases 64
默认连接的是index= 0的数据库,着16个库相互之间是独立的。类似于mysql服务器里的多个数据库
不同的应用程序数据存储在不同的数据库下。可以通select num来切换数据库
27. python操作redis的模块?
import redis
conn = redis.Redis(host=‘192.168.11.254‘,port=6379)
# 字符串
conn.set(‘key‘,‘value‘)
conn.get(‘key‘).decode(‘utf-8)
# 给字典设置和获取值
conn.hset(‘键值1‘,‘键值2’,‘value’)
conn.hget(‘键值1‘,‘键值2’)
conn.hgetall(‘键值1‘) #获取所有键值1的数据
conn.hdel(‘键值1‘,‘键值2’) # 删除键值2的值
# 其他用法
conn.keys(‘user1*‘) # #获取用户1的所有的key
conn.expire(键值1,timeout) #给键值1 设置一个超时时间,单位秒,过期自动删除
conn.flushall() # 清空
conn.exists(key) #判断键值是否存在
28. 如果redis中的某个列表中的数据量非常大,如果实现循环显示每一个值?
def list_iter(name):
"""
先取得列表的长度,在for循环长度,通过lindex对列表取值,返回yield
name:redis中的列表的key
返回列表元素
"""
list_count = r.llen(name) # llen() 获取列表长度
for index in range(list_count):
yield r.lindex(name,index) # lindex(naem,index) 通过索引找元素
29. redis如何实现主从复制?以及数据同步机制?
在redis中,用户可以通过执行slaveof命令,让一个服务器去复制另一个服务器,我们称呼被赋值的服务器为master
主服务器,而对主服务器进行复制的服务器称为从服务器。
redis1:127.0.0.1:6379
redis2:127.0.0.1:23456
127.0.0.1:23456> slavefo 127.0.0.1 6379
同步机制:
同步:当从服务器发送slaveof命令后,从服务器首先需要执行同步操作,将从服务器的数据库状态更新到主服务器所在的数据库状态。
命令传播:在执行完同步操作后,如果后续主服务器数据库状态变化,主服务器需要对从服务器进行命令传播操作:
主服务器会将自己执行过的命令(也就是造成主从不一致的命令),发送给从服务器,从服务器再执行,就同步了
30. redis中的sentinel的作用?
sentinel是redis官方推荐的高可用性(HA)解决方案。
Master-slave,master宕机,slave自动切换为master
不时地监控redis是否按照预期良好地运行;
能够进行自动切换,当一个master节点不可用时
31. 如何实现redis集群?
1.安装集群软件
# EPEL源安装ruby支持
yum install ruby rubygems -y
# 使用国内源
gem sources -a http://mirrors.aliyun.com/rubygems/
gem sources --remove http://rubygems.org/
gem sources -l
gem install redis -v 3.3.3
2、redis配置文件
port 7000
daemonize yes
pidfile /data/7000/redis.pid
logfile "/var/log/redis7000.log"
dbfilename dump.rdb
dir /data/7000
cluster-enabled yes # 开实例的集群模式
cluster-config-file nodes.conf # 保存节点配置文件的路径
cluster-node-timeout 5000
appendonly yes
启动6个节点(要让集群正常运作至少需要三个主节点,另外三个做为从节点)
/application/redis/src/redis-server /data/7000/redis.conf
/application/redis/src/redis-server /data/7001/redis.conf
/application/redis/src/redis-server /data/7002/redis.conf
/application/redis/src/redis-server /data/7003/redis.conf
/application/redis/src/redis-server /data/7004/redis.conf
/application/redis/src/redis-server /data/7005/redis.conf
ps -ef |grep 700
创建集群
/application/redis/src/redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001
127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
# 选项–replicas 1 表示我们希望为集群中的每个主节点创建一个从节点
# 之后跟着的其他参数则是这个集群实例的地址列表,3个master3个slave redis-trib 会打印出一份预想中的配
# 置给你看, 如果你觉得没问题的话, 就可以输入 yes
1
32. redis中默认有多少个哈希槽?
16384,使用哈希槽的好处是可以方便的添加或删除节点。
当需要在redis集群中放置一个k-v时候,然后通过对key进行CRC16校验后和16384取模
来计算放置在哪个槽里。
33. 简述redis的有哪几种持久化策略及比较?
Reids提供两种持久化方法:
1.Redis DataBase(RDB)
在不同的时间点,将redis存储的数据生成快照并存储在磁盘上。redis会单独fork一个子程序来进行持久化,主进程不会
进行任何IO操作,这样就确保了redis极高的性能。。RDB是每隔多长时间持久化一次
2.Append-only File(AOF)
将redis执行过的所有写指令都记录下来,在下次redis启动的时候,只需要把这些指令从前到后执行一遍就可以
实现了数据的恢复。。AOF的持久化策略是每隔一秒把缓存中的写指令记录到硬盘中。
如果要进行大规模的数据恢复,且对数据恢复的完整性不是非常敏感,那么RDB要比AOF更加高效。
如果对数据完整性非常敏感,那么就用AOF
34. 列举redis支持的过期策略。
三种过期策略:
1.定时删除
含义:在设置key的同时,为改key设置一个定时器,让定时器在key的过期时间来临时,对key进行删除
优点:保证内存尽快被释放
缺点:若key很多,删除会占用很多CPU时间;定时器的创建耗时,影响性能
2.惰性删除
含义:key过期的时候不删除,每次从数据库获取key的时候去检测是否过期,若过期,则删除,返回Null
优点:删除操作只发生在从数据库中取出key的时候,
缺点:若大量的key在超时候,很久一段时间内,都没有被获取过,那么可能发生内存泄漏(无用的垃圾占大量内存)
3.定期删除
含义:每隔一段时间删除过期的key操作
优点:通过限制删除操作的时长和频率,来减少对CPU时间占用--处理定时删除的缺点
定期删除过期的key--处理惰性删除的缺点
缺点:在内存友好方面不如定时删除
在cpu时间友好方面,不如惰性删除
难点:合理的设置删除操作的时长(每次删除多长时间)和执行的频率(每隔多长时间做一次删除)
35. MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中都是热点数据?
#redis 提供 6种数据淘汰策略:
voltile-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(驱逐):禁止驱逐数据
redis内存数据级上升到一定大小时,就会实行数据淘汰策略,
从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
36. 写代码,基于redis的列表实现 先进先出、后进先出队列、优先级队列。
1、FIFO队列:
class FIFO():
# lpush(‘list‘,val)进入--->[4,3,2]---> rpop(‘list‘)
def __init__(self,conn):
self.conn = conn
def push(self,vla):
self.conn.lpush(‘list‘,val)
def pop(self):
return self.conn.rpop(‘list‘)
2.后进先出队列:
class zhan():
def __init__(self,conn):
self.conn = conn
def push(self,val):
self.conn.rpush(‘list‘,val)
def pop(self):
return self.conn.rpop(‘list‘)
3.优先级队列:
class Prioriy():
def __init__(self,conn):
self.conn = conn
def push(self,val,count):
self.conn.zadd(‘list‘,val,count)
def pop(self):
a = self.conn.zrange(‘list‘,0,-1)[0]
self.conn.zrem(‘list‘,a)
return a
37. 如何基于redis实现消息队列?
1.什么是消息队列?
一个消息的链表,是一个异步处理数据的处理引擎
2.有什么好处?
不能能够提高系统负荷,还能够改善因为网络阻塞导致的数据缺失
3.用途有哪些?
邮件发送,日志存储,订单生成,
4.有哪些软件?
redis。。。。
5.怎么实现?
顾明思议,先入队,后出队;先把数据放到消息队列中(入队),后根据相应的key获取数据(出队)
6.Redis可以做消息队列?
首先,redis设计用来做缓存的,但是由于它自身的某种特性使得它可以用来做消息队列,它有几个阻塞的api可以使用
这些阻塞的api让其有能力做消息队列;做一个消息队列的其他特性如FIFO也很容易,只需要一个list对象从头取数据,从尾
部塞数据即可;redis能做消息队列还得益于其list对象blpop,brpop接口以及pub/sub(发布/订阅)的接口,它们都是阻塞
的。
redis提供了两种方式来作为消息队列:
1.生产者消费者模型:会让一个或多个客户端去监听消息队列,一旦消息到达,消费者马上消费(谁先抢到算谁的),
没有消息,继续监听
2.发布订阅者模型:也会让一个或多个客户端订阅消息频道,只要发布消息,所有的订阅者都能收到消息,订阅者都是平等的
38. 如何基于redis实现发布和订阅?以及发布,订阅和消息队列的区别?
Redis自带有PUB/SUB机制,即是发布-订阅模式。这种模式生产者和消费者是1-M的关系,即一条消息会被多个消费者消费,当
只有一个消费者的时候就是1-1的消息队列了。
pub/sub机制模型如下:publish是生产者,channel可以看做是一个发布消息的频道,只要client订阅(subscribe)了这个频道
,就能获取此频道的消息了
client1
publish ------> channel---->client2
client3
发布者和订阅者都是redis client端,channel是redis 服务端。发布者将消息发布到某个频道,订阅了这个频道的订阅者就能够收
到消息。
发布消息:publish first ‘hello‘ # 在first频道发布hello消息,其返回值为接收到该消息的订阅者的数量。
publish second ‘hello‘ # 在second频道发布hello消息,其返回值为接收到该消息的订阅者的数量。
订阅某个频道:
subscribe first second # 订阅了两个频道,其返回值包括客户端订阅的频道,目前已订阅的频道数量,
# 以及接收到的消息
39. 什么是codis及作用?
codis是一个分布式redis解决方案
40. 什么是twemproxy及作用?
twemproxy是一个memcached,redis的轻量级代理。有了twemproxy,客户端不用直接访问redis服务器,
而是通过twemproxy代理间接访问。
主要用于管理 Redis 和 Memcached 集群,减少与Cache 服务器直接连接的数量。
41. 写代码实现redis事务操作。
一般来说,事务有四个性质称为ACID,分别是原子性,一致性,隔离性和持久性。
a)原子性atomicity:redis事务保证事务中的命令要么全部执行要不全部不执行。有些文章认为redis事务对于执行错误不回滚违背了原子性,是偏颇的。
b)一致性consistency:redis事务可以保证命令失败的情况下得以回滚,数据能恢复到没有执行之前的样子,是保证一致性的,除非redis进程意外终结。
c)隔离性Isolation:redis事务是严格遵守隔离性的,原因是redis是单进程单线程模式,可以保证命令执行过程中不会被其他客户端命令打断。
d)持久性Durability:redis事务是不保证持久性的,这是因为redis持久化策略中不管是RDB还是AOF都是异步执行的,不保证持久性是出于对性能的考虑。
# 应用场景,如银行转账,等
import redis
pool = redis.ConnectionPool(host=‘127.0.0.1‘,port=6379)
conn = redis.Redis(connection_pool=popl)
# transaction默认为False,只可以完成批量提交的作用,节省网络延时
# 改为True后可以实现事务功能
pipe = conn.pipeline(transaction=True)
# 开始事务
pipe.multi()
pipe.set(‘name‘,‘zhangsan‘)
pipe.set(‘role‘,‘manager‘)
pipe.set(‘age‘,19)
pipe.execute() # 提交
# 用电商去库存,秒杀的时候举例
redis的事务可以认为是一段命令的批量执行和一次返回,事务操作本身没有问题,执行过程也不会中断。
但是在pipe.execute()的时候事务才真正的向redis_server提交,但是遗憾的是在redis_server执行之前
都有机会被其他用户修改,完全起不到锁库存的概念。
42. redis中的watch的命令的作用?
# 用电商去库存,秒杀的时候举例
redis的事务可以认为是一段命令的批量执行和一次返回,事务操作本身没有问题,执行过程也不会中断。
但是在pipe.execute()的时候事务才真正的向redis_server提交,但是遗憾的是在redis_server执行之前
都有机会被其他用户修改,完全起不到锁库存的概念。
watch可以看做数据库中的乐观锁的概念。
watch可以监控一个或多个键,一旦其中有一个键被修改、删除,之后事务就不在执行。
监控一直持续到exec命令。修改人保证自己的watch数据没有被其他人修改,否则自己就修改失败。
这里的watch相当于一个锁的。
如果在watch后值被修改,在执行pipe.execute()的时候会报异常WatchError: Watched variable changed.
# 代码实现
if __name__ == "__main__":
whit sms_redis.pipeline() as pipe:
while 1:
try:
# 关注一个key
pipe.watch(‘stock_count‘)
count = int(pipe.get(‘stock_count‘)
if count > 0: # 有库存
# 事务开始
pipe.multi()
pipe.set(‘stock_count‘,count-1)
# 事务结束
pipe.execute()
break
execpt Exception:
traceback.print_exc()
continue
43. 基于redis如何实现商城商品数量计数器?
if __name__ == "__main__":
whit sms_redis.pipeline() as pipe:
while 1:
try:
# 关注一个key
pipe.watch(‘stock_count‘)
count = int(pipe.get(‘stock_count‘)
if count > 0: # 有库存
# 事务开始
pipe.multi()
pipe.set(‘stock_count‘,count-1)
# 事务结束
pipe.execute()
break
execpt Exception:
traceback.print_exc()
continue
44. 简述redis分布式锁和redlock的实现机制。
为redis集群设计锁,防止多个任务同时修改数据库,其本质就是为了集群中的每一个主机设置一个
会超时的字符串,当集群中有一半多的机器成功后就认为加锁成功,直至锁过期。
45. 什么是一致性哈希?Python中是否有相应模块?
分布式算法:在做服务器负载均衡的时候可以选择的负载均衡算法有很多:
轮询,哈希,最少连接算法,响应速度算法,加权算法等等,其中哈希最长用。
典型应用场景:有N台服务器提供缓存服务,需要对服务器进行负载均衡,将请求平均分配到每台服务器上。
常用的算法是对hash结果取余(hash() mod N):对机器标号0-(N-1),按照自定义的算法,对每个请求的hash()值按N去模,
得到余数i,然后将请求分配到编号为i的机器上。这种算法存在致命问题,如果有服务器宕机,那么落在该服务器上的请求,无法得到正常
处理。这时需要将宕掉的服务器去掉,此时会有缓存数据需要重新计算,如果新增服务器,也需要对缓存数据进行重新计算。
对于系统而言,这是不可接受的颠簸。
from hash_ring import *
redis_server = [‘192.168.0.246:11212‘,
‘192.168.0.247:11212‘,
‘192.168.0.249:11212‘]
ring = HashRing(redis_server)
server = ring.get_node(‘my_key‘)
print(server) # ‘192.168.0.247:11212‘
server = ring.get_node(‘my_keysdfsdf‘)
print(server) # ‘192.168.0.249:11212‘
46. 如何高效的找到redis中所有以oldboy开头的key?
import
conn = redis.Redis(host=‘192.168.11.254‘,port=6379)
conn.keys(‘oldboy*‘)
47.redis列表命令?
blpop: # 命令移出并获取列表的第一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 (kay,value)
brpop: # 命令移出并获取列表的最后一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 值同上
lindex # 通过索引获取列表中的元素,0,1,2,……也可以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素
llen: # 获取列表长度
lpop: # 命令用于移除并返回列表的第一个元素。
rpop: # 命令用于移除并返回列表的最后一个元素。
lpush:# 命令将一个或多个值插入到列表头部。 如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作
rpush:# 命令用于将一个或多个值插入到列表的尾部(最右边)。 如果列表不存在,一个空列表会被创建并执行 RPUSH 操作
lpushx: # 将一个值插入到已存在的列表头部,列表不存在时操作无效。
rpushx: # 命令用于将一个值插入到已存在的列表尾部(最右边)。如果列表不存在,操作无效。rpush mylist ‘hello‘
lrange: # 返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定。 其中 0 表示列表的第一个元素, 1 表示列表的第二个元素,以此类推。 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
zrange: # 如果你需要以成员的值递减来排序,请使用zrange,下标参数start和stop都是以0为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员
eg:zrange(‘list‘,0,-1,id) # 按照id从大到小。排序
48.MongoDB和MySQL直接最基本的区别是什么,什么是MongoDB?
关系型数据库和非关系性数据库的区别,MongoDB是一个基于分布式文件存储的数据库,是非常灵活的数据库。MongoDB 文档类似于 JSON 对象
MongoDB的特点是什么?
(1)面向文档(2)高性能(3)高可用(4)易扩展(5)丰富的查询语言
MySQL MongoDB
DB DB 数据库
Table Collection Table概念
Row Document Row概念
Field Field 字段概念
_id 唯一概念,自动生成
MongoDB是基于文档存储的,基于关系型和非关系型数据库之间的产品。它支持的数据结果非常松散,类似于json。。
可以存储比较复杂的数据。
49.MongoDB要注意的问题
1 因为MongoDB是全索引的,所以它直接把索引放在内存中,因此最多支持2.5G的数据。如果是64位的会更多。
2 因为没有恢复机制,因此要做好数据备份
3.默认监听地址是127.0.0.1,port是27017
50.MongoDB基本指令
show dbs #查看所有数据库
use s11db #创建或使用数据库
db #查看当前所在的数据库
show tables #查看当前数据库的表
show collections #查看当前数据库的表
# 增加
db.user.insertOne({‘name‘:‘xiaoming‘,‘age‘:12}) #只能写字典
db.user.insertMany([{‘name‘:‘xiaoming‘,‘age‘:12},{‘name‘:‘xiaohua‘,‘age‘:14}]) #只能写列表套字典
# 删
db.user.remove({‘name‘:‘xiaoming‘}) # 删除符合的row
db.user.deleteOne({‘name‘:‘xiaoming‘}) # 删除符合的row
db.user.deleteOne({name:‘alex_sb‘,age:32}) # 逗号相当于AND
db.user.deleteMany({name:‘alex_sb‘}) #删除所有符合的
db.user.deleteMany({}) #清空数据
# 查
db.user.find() # 查询所有
db.user.findOne({"age":12}) # 等于12的
db.user.findOne({"age":{$gt:12}}) # 查询age大于12的
db.user.findOne({‘name‘:‘xiaoming‘,"age":{$gt:12}})
# 改
db.user.update({‘name‘:‘xiaoming‘},{$set:{‘name‘:‘老坛酸菜‘}}) # 把名字为xiaoming的改为老坛酸菜
db.user.update({‘name‘:‘xiaoming‘},{$set:{‘sex‘:‘男‘}}) # 给名字为xiaoming的增加一个属性sex并设置值
db.user.updateOne({‘name‘:‘xiaoming‘},{$set:{‘name‘:‘lisi‘}}) #符合条件的第一条数据
db.user.updateOne({‘name‘:‘xiaoming‘},{$set:{‘name‘:‘lisi‘}}) #符合条件的第一条数据
修饰器:
$set:将某个key的value修改为某个值,或增加属性 # {$set:{‘name‘:‘alex_sb‘}}
$unset: 删除字段 {$unset:{test:""}} #db.user.updateOne({"name":"alex"},{$unset:{"age":""}})
$lt,$lte,$gt,$gte…… #数学比较符
$:代指符合条件的某个数据对象,仅仅是查询的第一条数据
$inc:db.user.updateMany({},{$inc:{‘age‘:100}})#给所有的age加100,就算Document没有age字段也会按照初始零去相加
Array:
$push:向Array数据后面追加一个元素{$push:{‘name‘:‘alex‘}}
$pull:删除数组中的某一个元素 {$pull:{‘hobby‘:‘basketball‘}}
$pop:删除数组的第一个或最后一个
{$pop:{‘hobby‘:1}} 删除hobby数组最后一个
{$pop:{‘hobby‘:-1}} 删除hobby数组第一个
查询$关键字:
$in: 查询字段符合in中的数值 db.user.find(age:{$in:[11,12,13,14]})
$or: db.user.find({$or:[{age:1},{age:2}]})
$all: db.user.find({test:{$all:[2,1]}}) # array元素相同即可,包含即可。。。all的值是test的子集
排序:
db.user.find({}).sort({age:1}) #1升序(asc),-1降序(desc)
显示条目:
db.user.find({}).limit(2)# 只显示前两条
跳过:
db.user.find({}).skip(2)#从第三条开始显示
db.user.find({}).sort(‘age‘:1).skip(1).limit(2) # 可以做分页
删除表:db.表名.drop()
51.MongoDB的数据类型:
string
integer
double 包含float,MongoDB不存在Float类型,默认就是double
Null 空数据类型
Data
Timestamp
ObjectID "_id" : ObjectId("5b98709cb001ec5a59c6f78e"), Documents自动生成的 _id
52.python使用MongoDB
import pymongo
from bson import ObjectId
mclient = pymongo.MongeClient(host=‘127.0.0.1‘,port=27017)
mongo_db = mclient[‘s11db‘] # 连接或创建数据库
其他用法和在mongo中用法基本一样,有微小差别:
insertOne -- > insert_one # 其他操作一样
{$set:{‘sex‘:‘男‘}} ---> {"$set":{‘sex‘:‘男‘}}
mongo_db.user.find({}).sort(‘age‘,pymongo.DESCENDING) # 降序排序
mongo_db.user.find({}).sort(‘age‘,pymongo.ASCENDING) # 升序排序
其他一样
以上是关于RedisMySQLMongoDB相关面试题整理的主要内容,如果未能解决你的问题,请参考以下文章