当前位置:Gxlcms > 数据库问题 > Redis、MySQL、MongoDB相关面试题整理

Redis、MySQL、MongoDB相关面试题整理

时间:2021-07-01 10:21:17 帮助过:13人阅读


第三部分 数据库和缓存(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.TRIGGER\G;
        
    函数: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=‘heihei@163.com‘; # 不使用索引,
                   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-se

人气教程排行