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相关面试题整理的主要内容,如果未能解决你的问题,请参考以下文章

Java笔试面试题整理第一波

Android面试题集

牛客网真实面经总结—JVM篇

Android面试内容整理(持续收录中)

阿里二面JVM相关面试题

Java面试题