mysql

一 .mysql 架构

在这里插入图片描述在这里插入图片描述
1.主从
2.集群
3.分布式
(1)路由
(2)存储
(3实例

二.索引底层数据结构与算法

1.索引面试面试题优化
在这里插入图片描述
在这里插入图片描述2.索引的数据结构
mysql 底层 b+tree 和hash
(a). 二叉树:容易一条链到底单边增长,不会分叉.
(b). 红黑树:深度很长 (数据量大的时候深度会很深)
©. hash:用hash 不太适用于范围查找 比如a>5
(d). b-tree:每个节点(度)增加存储数量,且深度保持一样 ,横向发展 百万数据 最多6层 ,每个类型都是k,v 类型 k 索引 v数据值.
,但是mysql 是用b+tree(因为磁盘和内存的交互页的大小限制了交互 所以用了b+tree 把度里面只存key)
(e). b+tree : 把度里面只存key ,数据value 放在叶子结点 ,增加了指针叶子节点的尾元素和下一个叶子结点的元素相连(方便范围查找)

数据交互
javv<—>CPU <–>RAM<----如果内存没有才会去硬盘查找交互单位是页(4K)- 页多整数倍(根计算机硬件有关)–> 硬盘
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

3. 存储引擎 (是表级别不是数据库级别) 默认是innoDB

在这里插入图片描述
在这里插入图片描述

4.MYISAM 和innodb
两个文件个数不一样
(a.)MYISAM (.frm 表结构 .MYD 数据 .MYI 索引<key 加上索引的列名 值 ,data 是值的磁盘地址> )
非聚集索引
:主键索引 和其他列名索引存储相似 key 加上索引的列名 值 ,data 是值的磁盘地址

(b.)innodb (frm 表结构,ibd 数据+索引)
聚集索引(查询快,节省存储空间,数据一致性<一起存储减少分布式查找>)
主键索引 : key 加上索引的列名 值 ,data 整行记录保存
其他列索引:key 加上索引的列名 值 ,data 主键

innodb 必须要有主键 ,没有主键 默认会找一个做为主键
因为innodb 有一个主键文件,所以必须要有主键(要用自增主键<那让存储结构可以存在连续性>)

为什么用数字 不用uuid ?
(a) id 容易比较大小 字符串需要用ASCII 去比较 不容易比较大小,
(b) 而且id 容易有序排序 ,读取一页数据的时候方便范围查找.uuid 容易插入时候无序 且可能树分裂

5.联和索引的底层数据结构长什么样子?

在这里插入图片描述(a) 从第一个 一个一个比较.依次在第二个 一个一个比较
(b)

  1. inner join :组合两个表中的记录,返回关联字段相符的记录,也就是返回两个表的交集(阴影)部分。
    在这里插入图片描述left join
    left join 是left outer join的简写,它的全称是左外连接,是外连接中的一种。
    左(外)连接,左表(a_table)的记录将会全部表示出来,而右表(b_table)只会显示符合搜索条件的记录。右表记录不足的地方均为NULL。
    在这里插入图片描述

right join
right join是right outer join的简写,它的全称是右外连接,是外连接中的一种。
与左(外)连接相反,右(外)连接,左表(a_table)只会显示符合搜索条件的记录,而右表(b_table)的记录将会全部表示出来。左表记录不足的地方均为NULL。
在这里插入图片描述

7. explan 如果后面加extended 可以加拓展语句 比如:show warnings 优化后语句
a.表字段值
(1).id: id 列的序号是select的序列号 有几个select 就有几个id 并且id序号 按照select 出现顺序增长的 msql 将select查询分为简单查询(simple) 和复杂查询(praimary) 复查类查询分为:简单子查询 ,派生表(from 语句中的子查询),union 查询.id列越大执行优先级越高,id 相同则由上往下执行 id为null 最后执行
(2).select_type : 语句类型 表示是简单还是复杂查询 ,如果是复杂查询又是上述三种复杂查询中的一种
simple:简单查询,查询不包括子查询和unnion
primary :复杂查询中最外层select
subquery 包含在selec中的子查询 (不在from 子句中)
derived:包含from 子句中的子查询.mysql 会将结果存放在一个临时表中,也称为派生表
union: 在union中的第二个和随后的select
union resoult :从union 临时表检索结果的select
(3).table:表名

(4.)type(重点): 这一列表示关联类型 即mysql 决定如何查询表中的行,查找数据行记录的大概范围.依次最优到最差 system>const>eq_ef>ref>range>index>all 一般来说 要保证查询达到range级别 最高达到ref
null:mysql 能在优化阶段j分解查询语句,在执行阶段用不着在访问表或索引.例如在索引列选取最小值.可以单独来完成,不需要在只从时访问表.
cost: mysql 能对查询到某部分进行优化并将其转化为一个常量(可以看show warnings的结果) 用于primarykey或者unique key 的所有列与常数比较时,所以表最多有一个匹配行,读取一次.速度快.(根据主键或者唯一键查询 只会存在一条语句的).
system: 是const的特例 表里只有一条元组匹配是为system(查询的表就一条记录).
eq_ref:primary kry 或者unique key 索引的所有部分被连接使用,最多只会被返回一条符合条件的记录,这可能是在const 之外最好的 的连接类型,简单的select 查询不会出现这种 type.(作为关联使用,最多返回一条满足的记录)
ref:相比eq_ref 不实用唯一索引,而是使用普通索引或者唯一索引的部分前缀,索引要和某个值相比较,可能会找到多个条件的行(不是主键索引 是其他索引)
range:范围扫描通常出现在 in() ,between,>,<,>=,<=等操作中,使用一个索引来检索给定的范围.
index:扫描浅表索引,通常比all 快一些 (index是从索引中读取的,all 是从硬盘中读取的).
all : 全表扫描 意味着musql 需要从头到尾去查找所需要的行,通常情况下这个需要增加索引来进行优化了.
(5) ppssible_keys: 这一列显示查询可能使用哪些索引来查找.explan 时可能出现possible_keys 有列,而key 显示为null,这种情况是因为表中数据不多,mysql 认为索引对查询影响不大,选择全表查询.如果该列为null 则没有相关的索引,在这种情况下where 子句看是否可以创造一个适当的索引来提高查询性能.然后用explan 查看效果
(6)key: 这一列显示mysql 实际在用哪个索引来优化对表的访问,如果没有使用索引,则该列为null,如果请示mysql 使用或者忽视possible_keys列中的索引,在查询中使用 force index,ignore index.
(7)key_len: 这一列显示mysql 在索引列使用的字节数,通过这个值可以算出具体使用索引中的哪些列
举例来说.film_actor的联合缩影 idx_file_actor_id有film_id和actor_id两个int 列组成,并且每个int 4字节,通过结果中的 key_len =4 可以推断出查询使用了第一列:《film_id来执行索引查找.(表示走了哪个字段索引)》
《name varchar(10) =3*10+2 ,id int (4) =4 》 如果支持为null 还要+1
(8)ref: 这一列显示了在key列记录的索引中,表查找值所用到的列或者常量,常见的有:const(常量值) ,字段名(filn.id).(引用的是索引的值 还是字段)
(9)rows: 这一列是mysql 估计要读取并且检测的行数,注意这个不是结果集里面的行数.
(10)Extra: 这一列展示额外信息,常见的重要值如下:
using index: 查询的列被索引覆盖,并且where 筛选条件是索引的前导列(联合索引最左匹配),是性能高的表现.一般是使用了覆盖索引(索引包含了所查询的字段),对于innodb 来说,如果是辅助索引性能会有不少提高(select 里面的列 全是索引的,并且where 条件索引前导列)
user where:查询列未被索引覆盖,where 筛选条件非索引前导列(select 里面的列,不全都是索引列《select *》,并且where 条件也不是索引前导列)
using where using index:查询的列被索引覆盖,并且where筛选条件是索引列之一但是 不是索引的前导列.意味着无法直接通过索引查找来查询到符合条件的数据(select 里面的列 全是索引列,并且where 条件 有索引列之一 但不是索引前导列)
null:查询的列未被索引覆盖,并且where筛选条件是索引的前导列,意味着用到了索引,但是部分字段未被索引覆盖,必须通过“回表”来实现,不是单纯的用到索引,也不是完全没用到索引.(select 里面的列 不全是索引列,并且where 条件索引前导列)
using index condition: 与using where 类似,查询列不完全被索引覆盖,where 条件中是一个前导列的范围(select 里面的列,不全都是索引列《select *》,并且where 条件也索引前导列,范围查询《a>1》)
using tempory:mysql 需要创建一张临时表来处理查询.出现这种情况一般要进行优化的,首先想到用索引来优化.
(select distinct name from table name 没索引这种 《考虑把name 加索引就可以了》)
using filesort:mysql 会对结果使用一个外部索引排序,而不是按照索引次序从表里取行,此时mysql会跟据连接类型浏览符合条件的记录,并保存排序关键字和行指针,然后排序关键字并按顺序检索行信息,这种情况下一般也是要考虑索引优化.
(用order by name 排序 name 没索引这种 《考虑把name 加索引就可以了,因为索引提前排好序了》)

在这里插入图片描述

8. exist 和 in 原则
in 小表驱动打表,即小的数据集驱动大的数据集 (小的先执行)
exist 大表驱动打表,即小的数据集驱动小的数据集 (大的先执行)
在这里插入图片描述

存储过程:
··· demo1

drop procedure if exists kai_demo_procedure;

CREATE  PROCEDURE kai_demo_procedure (in delegationNo VARCHAR(32),out orderNum int,INOUT billNoInfo VARCHAR(128)
,out message VARCHAR(64),out caseMessage VARCHAR(64))
BEGIN 
-- 注意点:1.出入参数 如果是 VARCHAR 或者 CHAR 需要指定长度,不然报错;
--       2.逻辑处理部分 需要用 BEGIN AND 包裹;
--       3.out出参,不支持对象返回,如果单条记录且 返回的字段较少 可以用多个out,如果是集合可以用临时表;
--       4.出入参数名称或者 变量名称不要和表字段名称一样,如果一样给表取个别名;
--       5.into 使用 在一个select中只能出现一次,否则报错 具体demo 往下看 ***demo 这个标记的方法 举例:select a,b,c into A,B,C from table limit 1;
--       6.if 条件 结束需要 end if;  , elseif 不能写成 else if , if/elseif 记得加 then;

-- demo调用语法 :set @billNoInfo='提单号信息'; 
--              CALL kai_demo_procedure('2022081301',@orderNum,@billNoInfo,@message,@caseMessage);
--              SELECT @orderNum,@billNoInfo,@message,@caseMessage;

-- 声明局部变量 (变量分为四种:局部变量 (bengin......and 中有效),用户变量@age(当前连接有效),全局变量@@global.age(整个mysql服务器有效),会话变量 @@session.age(当前连接有效))
DECLARE bookingId BIGINT(20) DEFAULT 0 ;
DECLARE billNo VARCHAR(32);

-- 进行局部变量赋值
SET bookingId =747766892512256;

-- 用户变量 
set @englishName='KING';

-- 执行sql 语句 根据 set 赋值之后的bookingId进行查询
SELECT * from booking_order where booking_id =bookingId;

-- into  赋值 除了 set 之外的另一种赋值
SELECT bill_no into billNo FROM booking_order where booking_id =bookingId;
-- 根据 into 赋值之后的提单号进行查询
SELECT *  FROM booking_expand WHERE bill_no =billNo;

-- ***demo 根据传入的参数 delegationNo查询数量 并且返回出去 
  SELECT CONCAT(billNoInfo,':',GROUP_CONCAT(bill_no)),COUNT(1) into billNoInfo, orderNum FROM booking_expand WHERE delegation_no = delegationNo GROUP BY delegation_no;
 
 -- if 条件判断 
 if orderNum = 0 then 
	set message = '委托编号下面没有数据';
	elseif orderNum =1 then 
		set message = '委托编号下面存在1条数据';
	else 
	set message='委托编号下面数据大于1' ;
	end if;
	
	CASE
	when orderNum = 0 then 
	set caseMessage = '委托编号下面没有数据';
	when orderNum = 1 then 
	set caseMessage = '委托编号下面存在1条数据';
	else 
		set caseMessage='委托编号下面数据大于1' ;
		end case;
END 

set @billNoInfo='提单号信息';
CALL kai_demo_procedure('2022081301',@orderNum,@billNoInfo,@message,@caseMessage);

SELECT @orderNum,@billNoInfo,@message,@caseMessage;

demo2




drop procedure if exists kai_demo1_procedure;

CREATE PROCEDURE kai_demo1_procedure(in forParam INT,inout loopResp VARCHAR(128),inout repeatResp VARCHAR(128),inout whileResp VARCHAR(128))
BEGIN

-- 注意点 1.loop一定要有LEAVE 不然会死循环
--       2. while 和 loop,repeat 不同的是 不需要起别名
--       3.cursor游标 ,fetch 取的值 也是按照 select a,b,c from table ,a,b,c 顺序取的 
--       4.fetch坑: 循环中如果没有数据可以取会报异常 解决办法 1. 事先获取数量(按数量设置循环次数) 2. handler句柄处理
--       5.声明的游标 变量一定要放在最前面
--       6.具柄什么要放在游标后面
--       7. 动态创建表方式: prepare create_table_stmt FROM @create_table_sql; 后面不能使用局部变量 excute create_table_stmt;          DEALLOCATE prepare create_table_stmt;  

-- demo 调用 : set @loopResp='loop循环次数'; set @repeatResp='repeat循环多次次之后跳出循环'; set @whileResp='while循环多次次之后跳出循环';
--            call kai_demo1_procedure(0,@loopResp,@repeatResp,@whileResp); select @loopResp,@repeatResp,@whileResp; select * from temp_info;

-- 声明两个变量用于接收参数
declare groupName VARCHAR(64);
declare useStatus VARCHAR(32);
-- 声明变量用于控制是否继续循环
declare continueFlag boolean default true;

-- 声明游标 
declare cursor_demo cursor for  SELECT group_name,use_status from booking_order_group ;
-- 声明具柄 用于改变 continueFlag 值 
-- 1329 是错误码 具体自己去看 下面这句话的含义是 如果 发现异常码是1329(也可以用别名 02*** 对应的NOT FUND) 就把continueFlag变为false  继续(continue)往下走 这里如果用 exit   select forParam 这里就不会继续走了
declare continue handler for 1329 set continueFlag =false;


-- loop 循环 +leave(相当于java break) +iterate  
-- loop_demo 是循环的别名,如果 loop 和 end loop 之间没有 leave loop_demo; 这就是一个死循环;死循环解决办法 SHOW PROCESSLIST ; kill id;
	loop_demo:loop 
		set loopResp = CONCAT(loopResp,'-',forParam); 
		if forParam < 5 then 
		set forParam = forParam + 1; -- 自增
		iterate loop_demo;  -- 代表继续循环loop
		end if;
		LEAVE loop_demo; -- 离开循环
	end loop loop_demo;
-- 方便下面循环使用 赋值0
set forParam = 0;

-- REPEAT 循环demo  相当于 java do while 
repeat_demo :repeat 
set repeatResp = CONCAT(repeatResp,'-',forParam); 
	set forParam = forParam + 1; -- 自增
until forParam >5  -- forParam 大于5 跳出循环
end repeat repeat_demo;

-- 方便下面循环使用 赋值0
set forParam = 0;

-- while 相当于 java while 
while forParam <5 do 
set whileResp = CONCAT(whileResp,'-',forParam);  
set forParam = forParam + 1; -- 自增
end while;
	
-- 游标(cursor) + 句柄(handler) demo (把booking_order_group  放进临时表里)
-- 四个步骤 :1.声明 declare cursor_demo cursor for select * from table 2.打开 open cursor_demo 
--          3.逐个取值(fetch 一次 拿一行 需要配合 循环用) fetch  cursor_demo into a,b,c....., 4.关闭 close cursor_demo)

-- 创建临时表 temp_info
	 CREATE TEMPORARY TABLE IF NOT EXISTS temp_info (
        id INT AUTO_INCREMENT PRIMARY KEY,
        group_name varchar(64) NOT NULL COMMENT '分组名称',
        use_status varchar(32) NOT NULL DEFAULT '' COMMENT '使用状态: UNUSED -未使用  USED-已使用'
        );
				
-- 打开游标
open cursor_demo ;
-- 死循环取值
loop_cursor_demo: LOOP
 -- fetch  获取数据 ,这里是顺序获取列属性
  fetch cursor_demo into  groupName,useStatus;
	INSERT into temp_info (group_name,use_status) VALUES(groupName,useStatus);
	IF continueFlag=false THEN
		LEAVE loop_cursor_demo; 
	END IF; 
END LOOP loop_cursor_demo;
--  select forParam
-- 关闭游标
close cursor_demo;
END

set @loopResp='loop循环次数';
set @repeatResp='repeat循环多次次之后跳出循环';
set @whileResp='while循环多次次之后跳出循环';
call kai_demo1_procedure(0,@loopResp,@repeatResp,@whileResp);
select @loopResp,@repeatResp,@whileResp;
select * from temp_info


  myabtsi 调用
```java
 public ProcedureDemoResponse callProcedure() {

        Map<String, Object> params = new HashMap<>();
        params.put("forParam", 0);
        params.put("loopResp", "loop循环次数:");
        params.put("repeatResp", "repeat循环次数:");
        params.put("whileResp", "while循环次数:");
        //sqlSession 可以 接收出入参数
        try  {
            ProcedureDemoRepository mapper = sqlSession.getMapper(ProcedureDemoRepository.class);

            mapper.callProcedureDemo(params);

            String respInfo = (String) params.get("respInfo");
            System.out.println("respInfo: " + respInfo);
        }catch (Exception e){
            System.out.println("2222222");
        }

        //可以接收出入参数 接收不了 select *  from table limit 1
        Map<String, Object> map = new HashMap<>();
        map.put("forParam", 0);
        map.put("loopResp", "loop循环次数:");
        map.put("repeatResp", "repeat循环次数:");
        map.put("whileResp", "while循环次数:");
        procedureDemoRepository.queryCallProcedure(map);

        //如果 存储过程有 返回值不是出参的那种  里面有select *  from table limit 1可以用这种 接收
        ProcedureDemoResponse procedureDemoResponse = procedureDemoRepository.selectCallProcedure(0, "loop循环次数:", "repeat循环次数:", "while循环次数:");
        return procedureDemoResponse;
    }


```java
 public interface ProcedureDemoRepository {

    ProcedureDemoResponse selectCallProcedure(@Param("forParam") Integer forParam
            , @Param("loopResp") String loopResp, @Param("repeatResp") String repeatResp, @Param("whileResp") String whileResp);

    void queryCallProcedure(Map<String,Object> map);


    void callProcedureDemo(Map<String,Object> map);
}
  <select id="selectCallProcedure" resultMap="procedureResultMap" statementType="CALLABLE">
        {call kai_demo1_procedure(#{forParam, mode=IN, jdbcType=INTEGER}, #{loopResp, mode=INOUT, jdbcType=VARCHAR}, #{repeatResp, mode=INOUT,jdbcType=VARCHAR},
                                 #{whileResp, mode=INOUT,jdbcType=VARCHAR}, #{respInfo, mode=OUT,jdbcType=VARCHAR})}
    </select>


    <select id="queryCallProcedure" parameterType="java.util.Map" statementType="CALLABLE">
        {call kai_demo1_procedure(#{forParam, mode=IN, jdbcType=INTEGER}, #{loopResp, mode=INOUT, jdbcType=VARCHAR}, #{repeatResp, mode=INOUT,jdbcType=VARCHAR},
                                  #{whileResp, mode=INOUT,jdbcType=VARCHAR}, #{respInfo, mode=OUT,jdbcType=VARCHAR})}
    </select>


    <select id="callProcedureDemo" parameterType="java.util.Map" statementType="CALLABLE">
        {call kai_demo1_procedure(#{forParam, mode=IN, jdbcType=INTEGER}, #{loopResp, mode=INOUT, jdbcType=VARCHAR}, #{repeatResp, mode=INOUT,jdbcType=VARCHAR},
                                  #{whileResp, mode=INOUT,jdbcType=VARCHAR}, #{respInfo, mode=OUT,jdbcType=VARCHAR})}
    </select>


**细节:**

distinct,group by (执行执之前都会order by 一次), 子查询 会主动帮建临时表,不用临时表可以用索引字段

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值