一文掌握全部mysql面试题

文章目录

1.mysql慢查询相关命令
查看是否开启:show variables like '%slow_query%';
查看慢查询判定时长:show variables like '%long_query_time%';
设置慢查询判定时长:set long_query_time=5;
2.视图(虚拟的表)
创建:create view  视图名  as  select 字段名 from 表名
更新:alter view 视图名 as select 语句
删除:drop view 视图名
重命名:Rename table 视图名 to 新视图名
(修改视图会修改基表,避免此类操作)
3.mysql外键
CREATE TABLE `product` (
    `id` bigint(32) unsigned NOT NULL AUTO_INCREMENT COMMENT '产品id',
    `product_name` varchar(32) NOT NULL DEFAULT '' COMMENT '产品名',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='产品表'

CREATE TABLE `user_flow` (
    `id` bigint(32) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
    `order_id` varchar(32) NOT NULL DEFAULT '' COMMENT '订单申请id',
    `product_id` bigint(32) unsigned NOT NULL DEFAULT '0' COMMENT '产品id',
    CONSTRAINT product FOREIGN KEY(product_id) REFERENCES product(id),
    PRIMARY KEY (`id`),
    UNIQUE KEY `uniq_order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='流水表'
1)外键是父表的主键作为子表的字段
2)父表中没有,子表插入失败
3)子表中有,删除父表失败
4)查询用join on
4.count(*)和count(1)
1)有主键或联合主键的情况下,count(*)略比count(1)快一些。因为mysql数据库本身对于count(*)做了特别的优化处理。
2)没有主键的情况下count(1)比count(*)快一些。
3)count(字段),非主键字段,这样的使用方式最好不要出现。因为它不会走索引. 
4)count(*)和count(1)统计某个字段为null的行,count(字段)不统计当前字段为null的行
5)使用count()聚合函数后,不要跟where age=1 这样的条件,会导致不走索引,降低查询效率。除非该字段已经建立了索引。
   使用count()聚合函数后,若有where条件,且where条件的字段未建立索引,则查询不会走索引,直接扫描了全表。 
5.MySQL中varchar与char和int的长度问题
1)varchar与char的区别char(最大为255)是一种固定长度的类型,varchar则是一种可变长度的类型,char效率比varchar高
2)varchar(50)中50的涵义最多存放50个字符,varchar(50)和varchar(200)存储hello所占空间一样,但后者在排序时会消耗更多内存,因为order by col采用fixed_length计算col长度(memory引擎也一样)
3)int(20)中20的涵义是指显示字符的长度,也就是说int后面的数字和存储值的大小无关,具体int能存储的范围是多少,是根据int类型占用字节大小有关。(int有符号:2147483647)
4)mysql为什么这么设计对大多数应用没有意义,只是规定一些工具用来显示字符的个数。
(手册上还有这么一句话 "当 mysql 为某些复杂的联结 (join) 生成临时表时,你可能会遇到问题,因为在这种情况下,mysql 信任地认为所有的值均适合原始的列宽度")
6.delete、drop、truncate区别
删除数据的速度,drop> truncate > delete
delete属于DML语言,需要事务管理,commit之后才能生效。drop和truncate属于DDL语言,操作立刻生效,不可回滚。
使用场合:
    当你不再需要该表时, 用 drop;
    当你仍要保留该表,但要删除所有记录时, 用 truncate;
    当你要删除部分记录时(always with a where clause), 用 delete.
7.存储过程
就是把经常使用的SQL语句或业务逻辑封装起来,预编译保存在数据库中,当需要的时候从数据库中直接调用,省去了编译的过程.

优点

    1)存储过程可封装,并隐藏复杂的商业逻辑。
    2)存储过程可以回传值,并可以接受参数。
    3)存储过程无法使用SELECT等指令来运行,可以避免sql注入攻击,避免暴漏表结构和字段
    4)提高了运行速度,省去了编译的过程,同时降低网络数据传输量

创建

create procedure 存储过程名称([in 参数名 参数类型])
begin
    sql语句集合
end

使用

call 存储过程名称(参数);

查看

show procedure status;
show create procedure 存储过程名;

删除

drop procedure 存储过程名称;

if条件控制例子

create procedure demo1(in flag int)
begin
    declare a int default 10; //设置局部变量,及其默认值
    if flag > 10 then
        select * from table1 where id=flag;
    elseif flag > 100 then
        select * from table1 where id=a;
    else
        update table set id=flag
    end if;
end

while控制例子

create procedure demo1(in flag int)
begin
    declare a int default 0; //设置局部变量,及其默认值
    while a < flag do
         update table set id=a;
         set a=a=1;
    end while;
end
8.自定义函数

创建

create function function_name(参数列表)
    returns返回值类型
begin
    return 函数体
end;

删除

DROP FUNCTION IF EXISTS function_name;

查看

SHOW  CREATE FUNCTION hello;

使用

CREATE FUNCTION jic(a INT) RETURNS INT
BEGIN
	SET @i = 1;
	SET @result = 1;
	IF a = 0 THEN
		RETURN 0;
	ELSEIF a = 1 THEN
		RETURN 1;
	ELSE
		WHILE @i <= a DO
			SET @result = @result * @i;
			SET @i = @i +1;
		END WHILE;
		RETURN @result;
	END IF;
END
9.存储过程和函数的区别
1)存储过程和函数都是属于某个数据库。
2)函数需要在其他sql语句中调用才可以,而存储过程不能被其他调用,是自己执行通过call执行。
3)函数必须包含一个return语句
4)存储过程实现的功能要复杂一点,而函数的实现的功能针对性比较强。
    存储过程,功能强大,可以执行包括修改表等一系列数据库操作;用户定义函数不能用于执行一组修改全局数据库状态的操作。

image

10.mysql数据结构选择
    1)hash表
        (1)memory存储引擎使用的是hash表存储索引
        (2)innodb支持自适应hash,具体看38
        (3)hash碰撞,需要设计好的hahs函数
        (4)不支持范围查询
        (5)比较占用内存
    2)二叉树(二叉查找树):左边总比右边小,查找复杂度O(logn)

image

        (1)极端情况会变成如上图的链表,查询效率O(n)
    3)AVL树(严格平衡二叉搜索树):最长子树和最短子树高度差不能超过1
        (1)查找效率高,插入效率高
    4)红黑树(非严格平衡二叉搜索树):最长子树不超过最短子树高度的两倍
        (1)因为只有二叉,每层只能存两个数据,如果数据量太大,树的层数越来越高,会增加查询IO次数,降低查询效率
    5)B-树:有序多叉搜索树,节点存储数据

image

        (1)节点满了,再插入的时候是先拆后插,拆是从中间拆, 插是向叶子结点插入,中间节点只能是下层节点满了向上提升
        (2)当根结点满了,再有新数据插入时,先拆分提升根节点
        [构建过程](https://www.bilibili.com/video/BV1p7411k7nU)

image

image

6)B+树:有序多叉搜索树,中间节点不存储数据,叶子节点存储数据,并且叶子节点之间是双向链表
    (1)由于节点存数据,所以每层存的数据条数还是太小,因此把数据都存放在叶子结点,可以在不改变树的层数的情况下大大增大存储数据量

image

7)mysql-B+Tree
在原有B+Tree基础上,增加了一个指向相邻叶子节点的链表指针,就形成了带有序指针的B+Tree,提高了区间访问性能。
11.InnoDB和MyISAM有什么区别

image

1)InnoDB支持事物,而MyISAM不支持事物
2)InnoDB支持行级锁和表级锁,而MyISAM支持表级锁
3)InnoDB支持MVCC, 而MyISAM不支持(mvcc:多版本控制)
4)InnoDB支持外键,而MyISAM不支持
5)InnoDB早期版本不支持全文索引,而MyISAM支持。5.6版本后支持,使用ngram支持中文分词
6)InnoDB叶子结点存储数据,而MyISAM叶子结点存书地址
12.聚集索引

image

按照每张表的主键构造一颗B+树,同时叶子节点中存放的即为整张表的记录数据。聚集索引的叶子节点称为数据页,
聚集索引的这个特性决定了索引组织表中的数据也是索引的一部分。
主键是聚簇索引,即叶子节点就是数据,如果不指定主键,则mysql会自动设置表中合适(第一个组成列都not null的唯一索引作为聚簇索引)的字段,如果没有合适的则设置隐藏的
13.辅助索引(普通索引)
非主键索引,叶子节点=键值+书签。Innodb存储引擎的书签就是相应行数据的主键索引值。
(其实书签中存的就是聚集索引的数据页的索引值)
14.联合索引
当KEY `idx_uid_product_id_transmsn_time` (`uid`, `product_id`, `transmsn_time`)
会生成三个索引:uid, uid_product_id, uid_product_id_transmsn_time
where uid='123' and transmsn_time=123会走uid索引
where product_id=123 and uid=234 会走索引uid_product_id,mysql优化器会自动优化索引顺序
1)联合索引在B+树的存储结构[](https://www.cnblogs.com/ibigboy/p/12373978.html)

image
image

2)select * from a=1 and b=2 and c>3 and d<4(a,b,c,d联合索引,这种情况只走a,b索引)
15.覆盖索引
并不是指可以建立的一种索引,而是查询命中索引的一种行为
如果查询的列恰好是索引的一部分,那么查询只需要在索引文件上进行,不需要回行到磁盘再找数据。这种查询速度非常快,称为“索引覆盖”。
eg:联合索引字段,city和name,sql:select name from user where city='beijing';(走覆盖索引,不需要回表)
    索引name,sql:select city from user where name='zhangsan';(不走走覆盖索引,需要根据name找到聚簇索引id然后回表查询)
              sql:select id, name from user where name='zhangsan';(走覆盖索引,不用回表,因为name所以的b+树中包含id和name字段)
    主键索引:sql:select * from user where id=2;(走覆盖索引,不用回表,因为主键的b+树中包含所有信息)
聚簇索引和覆盖索引都不会回表查询
16.什么情况索引无效
    1.like 以%开头,索引无效;当like前缀没有%,后缀有%时,索引有效。
    2.or语句前后没有同时使用索引。当or左右查询字段只有一个是索引,该索引失效,只有当or左右查询字段均为索引时,才会生效
    3.组合索引,不是使用第一列索引,索引失效。
    4.数据类型出现隐式转化。如varchar不加单引号的话可能会自动转换为int型,使索引无效,产生全表扫描。
    5.在索引列上使用 IS NULL 或 IS NOT NULL操作。索引是不索引空值的,所以这样的操作不能使用索引,可以用其他的办法处理,
        例如:数字类型,判断大于0,字符串类型设置一个默认值,判断是否等于默认值即可。
    6.在索引字段上使用not,<>,!=。不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。
        优化方法: key<>0 改为 key>0 or key<0。
    7.对索引字段进行计算操作、字段上使用函数。(索引为 emp(ename,empno,sal))
    8.当全表扫描速度比索引速度快时,mysql会使用全表扫描,此时索引失效。
17.索引重建
1)可以先drop索引,在add新建索引
2)alter table table_name engine=InnoDB;
18.全文索引
create table fulltext_test (
    id int(11) NOT NULL AUTO_INCREMENT,
    content text NOT NULL,
    tag varchar(255),
    PRIMARY KEY (id),
    FULLTEXT KEY content_tag_fulltext(content,tag)  // 创建联合全文索引列
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

使用

select * from fulltext_test where match(content,tag) against('xxx xxx');
19.索引下推
mysql5.7之后才有的功能,针对联合索引
联合索引name和age
select * from table where name=zhangsan and age=12
没有索引下推前,先在存储引擎中找到name=zhangsan的所有数据,然后server层根据age=12过滤
有索引下推,直接在存储引擎中根据name=zhangsan和age=12过滤,然后再交给server层处理。
explain当Extra值为:Using index condition.表示使用索引下推。
20.mysql优化

image

1)通过explain查看sql执行流程
2)通过profiling查看执行耗时分析
    查看查询诊断工具状态:show variables like '%profil%';
    打开诊断工具:set profiling=1;
    执行sql语句
    查看sql语句ID:show profiles;
    根据id查看运行耗时情况:show profile all for query ID;

事件回顾:某天dba发来一个慢查询,让优化,然后用explain查看sql执行计划,发现走了索引。
        然后用通过profiling诊断工具查看运行过程耗时,发现sending data耗时严重。
        然后查看show variables like 'innodb_buffer_pool%'缓冲池大小,发现是1G,
        而数据库内存是4G,查询资料发现一般会设置成机器内存的75%~80%,然后让DBA修改配置,慢查询消失。

3)show processlist查看数据库链接状况
4)索引优化
5)数据类型优化
6)分库分表
7)查询优化
21.explain出来的各种item的意义
1)select_type:表示查询中每个select子句的类型
2)type:表示MySQL在表中找到所需行的方式,又称“访问类型”,ALL、index、range、 ref、eq_ref、const、system、NULL(从左到右,性能从差到好)
    ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行
    index: Full Index Scan,index与ALL区别为index类型只遍历索引树
    range:只检索给定范围的行,使用一个索引来选择行
    ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
    eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件
    const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,
    system是const类型的特例,当查询的表只有一行的情况下,使用system
    NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。
    
3)possible_keys:指出MySQL能使用哪个索引在表中找到行,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用
4)key:显示MySQL在查询中实际使用的索引,若没有使用索引,显示为NULL
5)key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度,key_len是根据表定义计算而得,不损失精确性的情况下,长度越短越好 
6)ref:表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
7)估算出结果集行数,表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数
8)Extra:包含不适合在其他列中显示但十分重要的额外信息
22.mysql日志种类
1)重做日志(redo log):(存储引擎层)又称重做日志文件,记录的是数据修改之后的值,确保日志的持久性,
    防止在发生故障,脏页未写入磁盘,重启数据库会进行redo log执行重做。
    如果数据库掉电,InnoDB存储引擎会使用redo log恢复到掉电前的时刻,以此来保证数据的完整性。
    在一条更新语句进行执行的时候,InnoDB引擎会把更新记录写到redo log日志中,然后更新内存,
    此时算是语句执行完了,然后在空闲的时候或者是按照设定的更新策略将redo log中的内容更新到磁盘中,
    这里涉及到WAL即Write Ahead logging技术,他的关键点是先写日志,再写磁盘。
    有了redo log日志,那么在数据库进行异常重启的时候,可以根据redo log日志进行恢复,也就达到了crash-safe。
2)回滚日志(undo log):保证数据的原子性,保存的是跟操作相反的操作,记录事务发生之前的一个版本,用于回滚,
    innodb事务可重复读和读取已提交的隔离级别就是通过mvcc+undo实现的。
3)二进制日志(bin log):(MySQL Server层)用于主从复制,实现主从同步
    事务提交的时候,一次性将事务中的sql语句(一个事物可能对应多个sql语句)按照一定的格式记录到binlog中。
4)错误日志(error log):Mysql本身启动,停止,运行期间发生的错误信息
5)慢查询日志(slow query log):记录执行时间过长的sql,时间阈值可以配置,只记录执行成功
6)一般查询日志(general log):记录数据库的操作明细,默认关闭,开启后会降低数据库性能
7)中继日志(relay log):用于数据库主从同步,将主库发来的bin log保存在本地,然后从库进行回放

ps:详细点击链接查看: https://blog.csdn.net/u010002184/article/details/88526708
ps1:磁盘的顺序写性能比内存的写性能差不了多少。
23.mysql二进制日志模式
1)satament(默认):只记录sql语句,日志量少,节约io,性能高,有些变化无法记录(时间相关的函数等),需要其他辅助信息
2)row:记录每行数据的改变,日志量大
3)mix:混合模式
24.事务
是一系列的操作,他们要符合ACID特性.最常见的理解就是:事务中的操作要么全部成功,要么全部失败。   
begin;  # 开启事务
select * from emp where id = 1 for update;  # 查询id值,for update添加行锁;
update emp set salary=10000 where id = 1; # 完成更新
commit; # 提交事务

1)原子性:依赖undo log
        一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。
        事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
2)一致性:依赖undo log
        保证事务只能把数据库从一个有效(正确)的状态“转移”到另一个有效(正确)的状态。
Table: Account
Columns:   Name(string), Balance(int)
约束条件:无
执行下面一个事务(A,B的初始余额均为1000,A给B转账1200)
    1.  往表Account插入数据(A,1000)
    2. 往表Account插入数据 (B,1000)
    3. A给B转账1200,更新A的余额为-200,(A,-200)
    4. B的余额增加1200,更新B的余额为2200(B,2200)
那么,数据库会认为这个 transaction 合不合法呢?也就是它满不满足我们给数据库的定义的规则呢?
答案就是这个 transaction 是合法的,因为你定义表的时候没有约定 Balance 不能小于0。
虽然我们从应用层的角度来看,这个transaction是不正确的,因为它不符合逻辑- balance不能小于0.  
但我们数据库只关心你的 transaction 满不满足你的数据库定义的rule,不关心它具有什么业务的逻辑,这个业务逻辑是应该由应用层来理解并处理的。
Table: Account
Columns:   Name(string), Balance(int)
约束条件:Balance >= 0
执行下面一个事务(A,B的初始余额均为1000,A给B转账1200)
    1.  往表Account插入数据(A,1000)
    2. 往表Account插入数据 (B,1000)
    3. A给B转账1200,更新A的余额为-200,(A,-200)
    4. B的余额增加1200,更新B的余额为2200(B,2200)
这里增加了约束条件Balance > 0, 上面的这个transaction违反了规则Balance>=0,
那么这个事务数据库认为它是非法的,不满足一致性的要求,所以数据库执行这个事务会失败。
3)隔离性:依赖mvcc实现
        数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
        比如多个账户同时往一个账户转钱,要保证最终结果和串行转入的结果一致
4)持久性:依赖redo log
        事务一旦提交,对数据的修改就是永久的,即便系统故障也不会丢失。
25.事务实现过程
1)在操作任务数据之前,首先将数据备份到Undo Log中,然后再进行数据的修改操作
2)出现错误时执行Roll Back,系统可以利用Undo Log恢复到事务开始之前的状态。
3)Redo Log是记录新数据的备份,事务提交之前,只将Redo Log持久化即可。
4)系统崩溃时,数据库未持久化,但Redo Log已经持久化,系统可以根据Redo Log将数据恢复并提交。
26.多事务的并发进行会造成以下问题
1)脏读: (A事务读取到了B事务==未提交==的内容)A事务读取到了B事务未提交的内容,而B事务后面进行了回滚.
2)不可重复读:(A事务读取到了B事务==修改或者删除==后提交的内容) 当设置A事务只能读取B事务已经提交的部分,会造成在A事务内的两次查询,结果竟然不一样,因为在此期间B事务进行了提交操作.
3)幻读:(A事务读取到了B事务==新增==提交的内容) A事务读取了一个范围的内容,而同时B事务在此期间插入了一条数据.造成"幻觉".
27.mysql四种隔离级别(解决26的问题)详情点击
1)未提交读(READ UNCOMMITTED)
    这就是上面所说的例外情况了,这个隔离级别下,其他事务可以看到本事务没有提交的部分修改。
    因此会造成脏读的问题(读取到了其他事务未提交的部分,而之后该事务进行了回滚).
    这个级别的性能没有足够大的优势,但是又有很多的问题,因此很少使用.
2)已提交读(READ COMMITTED)(解决脏读)(共享锁(读锁)实现)(MVCC实现,事务ID实现)
    其他事务只能读取到本事务已经提交的部分.这个隔离级别有不可重复读的问题,在同一个事务内的两次读取,
    拿到的结果竟然不一样,因为另外一个事务对数据进行了修改.
3)REPEATABLE READ(可重复读)(解决不可重复读)(MVCC实现,事务ID)
    可重复读隔离级别解决了上面不可重复读的问题(看名字也知道),但是仍然有一个新问题,就是幻读,
    当事务A读取id>10的数据行时,比如数据只有id=10,11,12,13的数据,mysql会对涉及到的所有行加上了读锁,
    此时事务B新插入了一条id=14的数据,因为是新插入的,所以不会触发上面的锁的排斥,
    那么事务A进行下一次的查询时会发现有一条id=14的数据,而上次的查询操作并没有获取到,再进行插入就会有主键冲突的问题.
    
    mysql RR 级别解决幻读是在一定的基础上的。这个基础就是,a 事务需要在 update 之前执行 select...for update。
    使用间隙()锁和临间锁(]
4)SERIALIZABLE(可串行化)(解决幻读)(幻读还以通过悲观锁解决,for updata 间隙锁和临间锁)
    这是最高的隔离级别,可以解决上面提到的所有问题,因为他强制将所以的操作串行执行,这会导致并发性能极速下降,
    因此也不是很常用.
5)nnoDB默认使用的是可重复读隔离级别

image

image

28.mvcc 详情点击

image

image

29.mysql锁分类

image

1)共享锁(读锁):其他事务可以读,但不能写,只有当所有读锁都解锁,才能修改。

image

2)排他锁(写锁):其他事务不能读取,也不能写。

image

ps:一种是来看房(读锁),多个用户一起看房是可以接受的. 一种是真正的入住一晚(写锁),在这期间,无论是想入住的还是想看房的都不可以.
3)意向锁

image

4)记录锁

image

5)间隙锁

image

6)临间锁

image

30.乐观锁和悲观锁
mysql的并发操作时而引起的数据的不一致性(数据冲突):
丢失更新:两个用户(或以上)对同一个数据对象操作引起的数据丢失。
    解决方案:
            1.悲观锁,假设丢失更新一定存在;sql后面加上for update;这是数据库的一种机制。
            2.乐观锁,假设丢失更新不一定发生。update时候存在版本,更新时候按版本号进行更新。
31.mysql锁-new
1)按照锁的模式分
    (1)共享锁(读锁,s锁)(属于行锁):对某一资源进行加锁后,其他人可以读,但是不能进行修改操作,其他人也可以加读锁
            select * from table lock in share mode
    (2)排他锁(x锁)(属于行锁):对某一数据进行加锁,其他人不能读,也不能写,同一时间只能有一个排他锁
            select * from table for update
    (3)意向锁(意向表锁)(属于表锁):不能手动添加,当表中添加共享锁或者排他锁的时候,会生成一个标记,就是意向锁,
            当需要对表加锁的时候需要先看意向锁有没有,就不用去表中便利所有数据了
        
2)按照锁的算法分
数据库数据:
    id      name
    1       a
    5       b
    9       c
    11      d
    (1)记录锁:锁本条数据
        select * from table where id=1 for update
        锁住id=1的数据
        
    (2)间隙锁:锁住一个区间内的数据
        select * from table where id > 5 and id < 9 for update
        锁住 (5,9] 区间的数据
        
        select * from table where id > 5 for update
        锁住 (5, 正无穷) 区间的数据
        
        select * from table where id > 15 for update
        锁住 (11, 正无穷) 区间的数据,注意不是 (15, 正无穷)
        
    (3)临间锁:锁住相邻间隔的区间的数据
        select * from table where id > 5 and id < 11 for update
        锁住 (5, 11] 区间的数据
        
        select * from table where id > 7 and id < 11 for update
        锁住 (5, 11] 区间的数据,和上边的相同
        
    (4)以上锁机制针对普通int型字段也可以
32.每个存储引擎支持的锁
1)MyISAM 和 MEMORY 存储引擎采用的是表级锁(table-level locking)
2)BDB 存储引擎采用的是页面锁(page-level locking),但也支持表级锁
3)InnoDB 存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。
33.雪花算法
用于分布式生成索引id,由于和时间相关,所以生成的id基本上保持自增,而且效率高(0+时间戳+机房号+机器号+同一毫秒内请求生成id的序号)
34.主从复制原理

image

1)主服务器上面的任何修改都会通过自己的 I/O tread(I/O 线程)保存在二进制日志 Binary log 里面。
2)从服务器上面也启动一个 I/O thread,通过配置好的用户名和密码, 连接到主服务器上面请求读取二进制日志,
    然后把读取到的二进制日志写到本地的一个Realy log(中继日志)里面。
3)从服务器上面同时开启一个 SQL thread 定时检查 Realy log(这个文件也是二进制的),如果发现有更新立即把更新的内容在本机的数据库上面执行一遍。
35.常见面试题
1)一张表,里面有ID自增主键,当insert了17条记录之后,删除了第15,16,17条记录,再把Mysql重启,再insert一条记录,这条记录的ID是18还是15 ?
    myisam:18
    innodb:15(最大id在内存中)
36.mysql瓶颈
单表500w数据后性能下降较快
37.创建索引是用int类型还是varchar类型
哪个小用哪个,因为占用数据量越小,索引占用空间越小,可以存的数据越多
mysql一般索引层数为3-4层,因为足以支持4千万级别的数据,具体多少层由mysql根据数据量大小自动设置
每个数据页为16kb,每个索引占10字节,叶子结点每个数据1kb,1600*1600*16=40960000

image

38.为啥主键一般选择自动递增的
1)涉及到索引B+树的维护过程,如果不是递增的,则会需要频繁的改变索引树的结构和层数,频繁的进行页分烈和页合并
2)如果用递增的id,则只会再索引树最后直接append,不会改变之前的树结构
39.join执行顺序
select name from tb1 a join tb2 b on a.id = b.id;
并不一定先读表tb1后读表tb2,由mysql优化器自动选择
可以采用如下方式强制按顺序执行
select straight_join name from tb1 a join tb2 b on a.id = b.id;
40.mysql优化器
1)CBO:基于成本的优化:基于效率
2)RBO:基于规则的优化:给予指定的规则
41.innodb自适应hash
Innodb存储引擎会监控对表上二级索引的查找,如果发现某二级索引被频繁访问,二级索引成为热数据,建立哈希索引可以带来速度的提升
42.创建索引字段是长了好还是短了好
短了好,层数不变的情况下能存更多的数据
43.mysql高水位问题
触发原因:频繁删除数据、插入数据导致索引不连续带来的页内数据空洞,表实际占用空间增大
解决办法:alter table table_name engine = InnoDB
          相当于建立临时表,把表删除后,重新插入数据,重建表
44.查询字段类型和定义类型不同时出现的问题
数据库定义order_id varchar(32)
查询语句:select * from table where order_id=123456789012345678
查询结果可能对不上
原因:mysql在输入超过16位时解析器会将输入转化为二进制,转化时会有精度损失,导致查询失败
db_risk_host = 'rc_policy_m.db.xiaoying.io'
db_risk_db = 'yingzhongtong_risk_system'
这个库的liveverify_applyinfo这个表,执行查询语句的时候对不上了
select * from  liveverify_applyinfo where order_no = 216397821490495472
结果查出来的数据的order_no为216397821490495493
45.分组,排序相关
数据库字段:id, nianji, banji, uid, xueke, fenshu
1)求各班的语文的平均成绩
select nianji, banji, avg(fenshu) from table where xueke='yuwen' group by nianji, banji
2)找出一年级一班总成绩最高的三名学生
select uid,sum(fenshu) as a from table where nianji='yinianji' and banji='yiban' group by uid order by a desc limit 3
3)找出每个年级每个班的总分前三名(分数相同,并列)
select nainji, banji, uid
from (
	select * ,dense_rank() over (partition by nianji, banji order by score )r
	from 
			(
				select nainji, banji, uid, sum(fenshu) as score
				from table
				group by nianji, banji,uid
			)a
	)b
where r <= 3
4)rank:1,1,3
   dense_rank:1,1,2
   row_numbe:1,2,3
46.时间函数
1)now(),sysdate(),current_timestamp,current_timestamp(),unix_timestamp():now返回当前时间,sysdate也返回当前时间,但是在同一个语句中动态获取
mysql> select now(),sysdate(),current_timestamp,current_timestamp(),unix_timestamp();
+---------------------+---------------------+---------------------+---------------------+------------------+
| now()               | sysdate()           | current_timestamp   | current_timestamp() | unix_timestamp() |
+---------------------+---------------------+---------------------+---------------------+------------------+
| 2021-01-13 13:10:29 | 2021-01-13 13:10:29 | 2021-01-13 13:10:29 | 2021-01-13 13:10:29 |       1610514629 |
+---------------------+---------------------+---------------------+---------------------+------------------+

mysql> select now(), sleep(3), now();
+---------------------+----------+---------------------+
| now()               | sleep(3) | now()               |
+---------------------+----------+---------------------+
| 2021-01-13 11:20:56 |        0 | 2021-01-13 11:20:56 |
+---------------------+----------+---------------------+
mysql> select sysdate(), sleep(3), sysdate();
+---------------------+----------+---------------------+
| sysdate()           | sleep(3) | sysdate()           |
+---------------------+----------+---------------------+
| 2021-01-13 11:21:12 |        0 | 2021-01-13 11:21:15 |
+---------------------+----------+---------------------+
2)date_formt
    (1)按日查询
SELECT DATE_FORMAT(created_date,'%Y-%m-%d') as time,sum(money) money FROM o_finance_detail where org_id = 1000  GROUP BY  time
    (2)按月查询
SELECT DATE_FORMAT(created_date,'%Y-%m') as time,sum(money)  money FROM o_finance_detail where org_id = 1000  GROUP BY  time
3)时间转化函数
    (1)date_add()和date_sub()
mysql> set @dt = '2008-08-09 12:12:33';
mysql> select date_add(@dt, interval '1 01:15:30' day_second);
+-------------------------------------------------+
| date_add(@dt, interval '1 01:15:30' day_second) |
+-------------------------------------------------+
| 2008-08-10 13:28:03                             |
+-------------------------------------------------+

mysql> select date_sub('1998-01-01 00:00:00', interval '1 1:1:1' day_second);
+----------------------------------------------------------------+
| date_sub('1998-01-01 00:00:00', interval '1 1:1:1' day_second) |
+----------------------------------------------------------------+
| 1997-12-30 22:58:59                                            |
+----------------------------------------------------------------+
    (2)datediff(date1,date2), timediff(time1,time2)
mysql> select datediff('2008-08-08', '2008-08-1');
+-------------------------------------+
| datediff('2008-08-08', '2008-08-1') |
+-------------------------------------+
|                                   7 |
+-------------------------------------+

mysql> select datediff('2008-08-08', '2008-07-08');
+--------------------------------------+
| datediff('2008-08-08', '2008-07-08') |
+--------------------------------------+
|                                   31 |
+--------------------------------------+

mysql> select timediff('2008-08-08 08:08:08', '2008-08-08 00:00:00');
+--------------------------------------------------------+
| timediff('2008-08-08 08:08:08', '2008-08-08 00:00:00') |
+--------------------------------------------------------+
| 08:08:08                                               |
+--------------------------------------------------------+

mysql> select timediff('2008-08-08 08:08:08', '2008-08-07 00:00:00');
+--------------------------------------------------------+
| timediff('2008-08-08 08:08:08', '2008-08-07 00:00:00') |
+--------------------------------------------------------+
| 32:08:08                                               |
+--------------------------------------------------------+
4)截取函数substr():第三个参数是长度
select * from table where sbustr(create_time,1,10) = '2020-09-08';
47.mysql分库分表平滑扩容 详情点击
    1)停服更新:不推荐
    2)升级从库
        (1)修改分片配置,做好新库和老库的映射。
        (2)同步配置,从库升级为主库
        (3)解除主从关系
        (4)冗余数据清理
        (5)为新的数据节点搭建新的从库

image

3)双写迁移

image

48.mysql一个表索引多少比较合适
一个表哪怕只做查询操作,索引也不宜过多, 因为所以太多会导致查询选择索引出现开销(当然指定了索引可以最低限度的降低开销).
从我自己的实际工作情况来看, 所以得建立要全局考虑,就是不要仅仅只考虑一张表的索引怎么建,
而是要考虑你整个模块应用的索引怎么建,一般在一个表上索引不要超过5个!
49.关于mysql分页查询大数据量offset过大的查询速度变慢
-- 以该查询为例
select * from table where field='' limit n,m
假设该查询走了索引,该查询会查询出前n + 1条数据,根据条件去掉前n条,如果n太大,则会有多次回表操作导致查询效率降低
优化方式
如果单表数据量比较大,可通过减少回表次数提高效率,所以可以对上面的查询语句做下简单的修改
select * from table a inner join (select id from table where where field='' limit n,m) b on  a.id=b.id

如果每页分页数据量不大,也可以用子查询,如果m值太大,不建议使用,可能会导致索引失效
select * from table where id in (select id from (select id from table where where field='' limit n,m) b)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值