当前位置: 首页 > news >正文

黑马数据库学习笔记

课程地址

(基础篇)MySQL的启动

mysql 默认使用 3306 端口

在 centos下,启动 mysql 数据库:service mysqld start;

查看状态/启动/停止/重启:systemctl status/start/stop/restart mysqld;

登录到mysql数据库:mysql -uroot -psyc13140;

MySQL的层次结构为:用户,数据库,表

关系型数据库:RDBMS,Relational Database Management System。建立在关系模型理论的基础上,由多张连接的二维表组成的数据库

在这里插入图片描述

查看数据库和表:

show databases;use db1;
select database();	# 查询当前数据库
show tables;

MySQL数据类型

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

SQL语言分类

CRUD:cerate retrive update delete

在这里插入图片描述

DDL

数据定义语言:数据库的定义,数据库表的定义,字段的定义

show databases;		-- 查看所有数据库
select database();	-- 显示当前使用的数据库create database [if not exists] mydb1 [default charset utf8mb4] [collate utf8mb4_general_ci];
alter database mydb1 character set utf8;
drop database [if exists] mydb1;show tables;
create table emp(id int [comment ""],name varchar(20) [comment ""],sex int [comment ""],birthday date [comment ""],salary double [comment ""],hiredate date [comment ""],resume text [comment ""]
) [comment ""];desc emp;	# describe emp
show create table emp;	# 查看建表过程
drop table emp;

创建表

在这里插入图片描述

create table tb_user(id int comment "id",name varchar(20) comment "name",age int comment "age",gender varchar(1) comment "gender"
)comment "user table";

执行sql脚本:

source /home/daniel/scott.sql;

创建表练习:

在这里插入图片描述

create table emp(id int,work_no varchar(10),name varchar(10),gender char(1),age tinyint unsigned,id_card char(18),entry_date date
);

修改表

alter table emp add nickname varchar(20) comment "昵称";
alter table emp modify nickname varchar(25);
alter table emp change nickname username varchar(30);
alter table emp drop username;
alter table emp rename to worker;

删除表

drop table worker;
truncate table worker;	# 删除表,并重新创建该表

小结

# 数据库操作
show databases;
create database db_name;
user db_name;
select database();
drop database db_name;# 表操作
show tables;
create table tb_name(field1, field2, ...);
desc tb_name;
show create table tb_name;
alter table tb_name add/modify/change/drop/rename to ...;
drop table tb_name;

DML

insert into tb_name(field1, field2, ...) values (value1, value2...);
insert into tb_name values(v1, v2);
# 批量添加数据
insert into tb_name (f1, f2, ...) values (value1, value2...), (value1, value2...), (value1, value2...);
insert into tb_name values (value1, value2...), (value1, value2...), (value1, value2...);

对于这样一张表:

create table emp(id int,name varchar(20),sex int,birthday date,salary double,hiredate date,resume text
);
# insert into tb(field1, field2, field3) values(value1, value2, value3);
insert into emp values(1,'daniel',1,'1999-10-19',50000,'2023-10-10','i hope so');
update emp set salary=salary+5000;
delete from emp where name='daniel';
delete from emp;	# 删除所有数据!

如果插入的数据已存在,则使用 ignore 修饰 insert

insert ignore into actor values(3, "ED", "CHASE", "2006-02-15 12:34:33");

DQL

SELECT字段列表
FROM表名列表
WHERE条件列表
GROUP BY分组字段列表
HAVING分组后条件列表
ORDER BY字段1 排序方式1, 字段2 排序方式2
LIMIT	# 分页[<offset>,] <row count>]
select deptno, dname, loc from dept;
select empno, ename, sal, sal*12 as package from emp;	# as起别名
select distinct city from user_profile;		# 去重

where

在这里插入图片描述

select * from emp where sal=800 and deptno=20;	# 查找部门编号为20,薪水为800的员工
select * from emp where deptno in (20, 30);		# 查找部门编号为20或30的员工
select name from emp where idcard is null;

在解析where条件时, 是从右向左解析的,所以应该将容易假的值放在右边,利用逻辑短路特性

like

%:匹配任意多个字符
_:匹配任意一个字符

select * from emp where ename like 'S%';	# 查询名字以S开头的员工
select * from emp where ename like '____';	# 查询名字中有四个字母的员工

group by

在这里插入图片描述

# 分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义
select gender, count(*) from emp group by gender;
select gender, avg(age) from emp group by gender;# 查询年龄小于45岁的员工,并根据工作地分组,获取员工数量>=3的地址
select workaddress, count(*)
from emp
where age < 45
group by workaddress
having count(*) >= 3;

order by

select * from emp order by age asc;
select * from emp order by entrydate desc;
select * from emp order by age asc, entrydate desc;

limit

select * from article limit 1,3		# 取第2 3 4条数据

DQL练习:

在这里插入图片描述

select * from emp where age <= 23 and age >= 20;
select * from emp where gender = "男" and age between 20 and 40 and name like "___";
select gender, count(*) from emp where age < 60 group by gender;
select name, age from emp where age <= 35 order by age, entrydate desc;
select * from emp where gender = "男" and (age between 20 and 40) order by age, entrydate limit 5;

DQL的执行顺序

在这里插入图片描述

函数

聚合函数

将一数据作为一个整体,进行纵向计算。包括:count max min avg sum等

主要应用于 group by 分组操作

select count(*) from emp;	# null不参与聚合函数计算
select avg(age) from emp;

字符串函数

在这里插入图片描述

select concat("hello", "mysql");
select lower("Hello");
select upper("Hello");
select lpad("1", 5, "0");
select rpad("1", 5, "0");
select trim("   hello world   ");
select substring("hello, mysql", 1, 5);-- 使用逗号分隔结果
select dept_no, group_concat(emp_no) as employees
from dept_emp
group by dept_no;

在这里插入图片描述

update emp set workno = lpad(workno, 5, "0");

数值函数

在这里插入图片描述

select ceil(1.4);
select floor(1.9);
select mod(7, 4);
select rand();	// 生成 (0, 1) 之间的验证码
select round(3.1415926, 3);

通过数据库的函数,生成一个6位数的随机验证码:

select lpad(round(rand() * 1000000, 0), 6, "0");

日期函数

在这里插入图片描述

取日期中的年月日:

select curdate();
select curtime();
select now();select year(now());
select month(now());
select day(now());select date_add(now, interval 70 day);
select datediff("2021-12-01", "2021-11-01");

查询所有员工的入职天数,并根据入职天数倒序排序:

select name, datediff(now(), entrydate) as days from emp order by days desc;

求时间差:

timestampdiff(MINUTE, start_time, submit_time)

流程控制函数

在这里插入图片描述

select if(true, "ok", "default");
select ifnull("ok", "default");
select ifnull(null, "default");

查询emp表的员工姓名和工作地址,如果工作地址为北京或上海,则显示一线城市;否则显示二线城市

selectname,( case workaddress when "北京" then "一线城市"when "上海" then "一线城市"else "二线城市"end ) as "工作地点"
from emp;

根据成绩显示结果:

selectname,( casewhen score >= 85 then "优秀"when score >= 60 then "及格"else "不及格"end) as "成绩"
from stu;

约束

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

create table user (id int primary key auto_increment,name varchar(10) not null unique,age int check(age > 0 and age <=120),status char(1) default "1",gender char(1)
)comment "用户表"

外键约束

外键用于建立两张表数据之间的连接,从而保证数据的一致性和完整性

在这里插入图片描述

alter table emp add constraint fk_emp_dept_id foreign key (dept_id) references dept(id);
alter table emp drop foreign key fk_emp_dept_id;

一般是不允许直接删除父表的外键记录的,因为子表有很多记录关联到了父表

删除更新行为

在这里插入图片描述

alter table emp
add constraint fk_emp_dept_id
foreign key (dept_id)
references dept(id)
on update cascade
on delete cascade;

多表查询

多表关系

多对一:

在这里插入图片描述

多对多:创建一张中间表

在这里插入图片描述

一对一:一般用作单表拆分

在这里插入图片描述

多表查询

多表查询的过程其实就是构造多个表的一个笛卡尔积,然后利用连接条件筛选出正确的结果,消除无效的笛卡尔积

在这里插入图片描述

select * from emp, dept where emp.dept_id = dept.id;

在这里插入图片描述

内连接

查询两张表的交集部分

隐式内连接:

select emp.name, dept.name from emp, dept where emp.dept_id = dept.id;select e.name, d.name
from emp as e, dept as d	-- 如果已经为表起了别名,则后面引用表时不能再用原表名,必须使用别名
where e.dept_id = d.id;

显式内连接(使用 on 连接):

select e.name, dept.name
from emp as e inner join dept as d
on emp.dept_id = dept.id;

外连接

select * from tb1 left outer join tb2 on cond;		-- 查询左表
select * from tb1 right outer join tb2 on cond;		-- 查询右表
-- 查询emp表的所有数据,和对应的部门信息
select e.*, d.name
from emp as e left outer join dept as d
on e.dept_id = d.id;-- 查询dept表的所有数据,和对应的员工信息
select d.*, e.*
from emp as e right outer join dept as d
on e.dept_id = d.id;

自连接

自连接查询,可以是内连接查询,也可以是外连接查询

查询员工,及其所属领导的名字:

select worker.name, leader.name from emp as worker, emp as leader where worker.managerid = leader.id;select worker.name, leader.name
from emp as worker inner join emp as leader
on worker.managerid = leader.id;

查询所有员工emp及其领导的名字emp,如果员工没有领导,也需要查询出来(使用外连接):

select a.name as "worker", b.name as "leader"
from emp as a left outer join emp as b
on a.managerid = b.id;

联合查询

将多次的查询结果合并起来,形成一个新的查询结果集

-- 将薪资 < 5000的员工和年龄 > 50的员工全部查询出来
select * from emp where salary < 5000
union all
# union -- 会去重
select * from emp where age > 50;

联合查询的多张表的列数和每列的字段类型必须保持一致。union会将结果去重;union all会直接将数据合并在一起

子查询

在这里插入图片描述

标量子查询

查询“销售部”的所有员工信息:

select * from emp where dept_it = (select id from dept where name = "销售部");

查询在“方东白”入职之后的员工信息:

select * from emp where entrydate > (select entrydate from emp where name = "方东白");

列子查询

在这里插入图片描述

-- 查询销售部和市场部的所有员工信息
select * from emp where dept_id in (select id from dept where name = "销售部" or name = "市场部");-- 查询比财务部所有人工资都高的员工信息
select *
from emp
where salary > all(  -- max(select salaryfrom empwhere dept_id = (select idfrom deptwhere name = "财务部")
);-- 查询比研发部任意一人工资高的员工信息
select * 
from emp 
where salary > any(  -- min( -- some(select salaryfrom empwhere dept_id = (select idfrom deptwhere name = "研发部")
);

行子查询

-- 查询与“张无忌”薪资和直属领导相同的员工信息
select *
from emp
where (salary, managerid) = (	--( tuple equalsselect salary, manageridfrom empwhere name = "张无忌"
);

表子查询

-- 查询与“鹿仗客”,“宋远桥”的职位和薪资相同的员工信息
select *
from emp
where (job, salary) in (select job, salaryfrom empwhere name = "鹿仗客" or name = "宋远桥"
);-- 查询入职日期是“2006-01-01”之后的员工信息和部门信息
select e.*, d.*
from (select *from empwhere entrydate > "2006-01-01"
) as e left join dept as d
on e.dept_id = d.id;

案例练习

三张表:emp dept salgrade

在这里插入图片描述

-- 1 查询员工的姓名,年龄,职位,部门信息 隐式内连接
select e.name, e.age, e.job, d.name
from emp as e, dept as d
where e.dept_id = d.id;-- 2 查询年龄小于30岁的员工姓名,年龄,职位,部门信息 显式内连接
select e.name, e.age, e.job d.name
from emp as e inner join dept as d
on e.dept_id = d.id
where e.age < 30;-- 3 查询拥有员工的部门id,部门名称
select distinct d.id, d.name
from emp as e, dept as d
where e.dept_id = d.id;-- 4 查询所有age > 40的员工,及其归属的部门名称;如果员工没有分配部门,也需要展示出来 左外连接
select e.*, d.*
from emp as e left outer join dept as d
on e.dept_id = d.id
where e.age > 40;-- 5 查询所有员工的工资等级
select e.*, s.grade
from emp as e, salgrade as s
where e.salary >= s.lowsal and e.salary <= s.highsal;-- 6 查询“研发部”所有员工的信息及工资等级
select e.*, s.grade
from emp as e,salgrade as s,dept as d
wheree.dept_id = d.id ande.salary between s.lowsal and s.highsal andd.name = "研发部";-- 7 查询“研发部”员工的平均工资
select avg(e.salary)
from emp as e, dept as d
where e.dept_id = d.id and d.name = "研发部";-- 8 查询工资比“灭绝”高的员工信息 标量子查询
select *
from emp
where salary > (select salary from emp where name = "灭绝"
);-- 9 查询比平均薪资高的员工信息 
select *
from emp
where salary > (select avg(salary) from emp
);-- 10 查询低于本部门平均工资的员工信息
select *
from emp as e1
where e1.salary < (select avg(e2.salary)from emp as e2where e1.dept_id = e2.dept_id
);-- 11 查询所有部门的信息,并统计部门的员工人数
selectd.id,d.name, (select count(*) from emp as e where e.dept_id = d.id) as "人数"
from dept as d;-- 12 查询所有学生的选课情况,展示出学生名称,学号,课程名称
select s.name, s.no, c.name
from student as s, course as c, student_course as sc
where s.id = sc.studentid and c.id = sc.courseid;

事务

事务是指一组操作的集合,它是一个不可分割的工作单位,事务会把所有操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败

在这里插入图片描述

MySQL的事务默认是自动提交的,也就是说,当执行一条DML语句,MySQL会立即地隐式提交事务

建表:

create table account (id int primary key auto_increment,name varchar(10),money int
);insert into account
values(1, "zhangsan", 2000),(2, "lisi", 2000);-- 恢复数据
update account set money = 2000 where name = "zhangsan" or name = "lisi";
-- 查看/设置事务提交方式
select @@autocommit;
set @@autocommit = 0;
-- 提交事务
commit
-- 回滚事务
rollback

如果设置了手动提交,则执行DML语句后,数据库的内容不会发生变化,直到commit

set @@autocommit = 0;
update account set money = money - 1000 where name = "zhangsan";
update account set money = money + 1000 where name = "lisi";-- 直到执行commit
commit

临时开启一个事务:

begin -- start transaction 

总结,使用事务有2种方式:

  • 通过 set @@autocommit = 0 关闭自动提交,全部手动commit/rollback
  • 通过 begin 开启一个事务

ACID

在这里插入图片描述
并发事务的3个问题,多个并发事务在操作数据库时引发的问题:

  • 脏读:一个事务读到另一个事务还没有提交的数据
  • 不可重复读:一个事务先后读取同一条记录,但两次读取的数据不同(中间被update了)
  • 幻读:一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在

事务的隔离级别

在这里插入图片描述

查看/设置事务的隔离级别:

select @@transaction_isolation;
-- set [session | global] transaction isolation level {read uncommitted | read committed | repeatable read | serializable};
set session transaction isolation level read uncommitted;

事务隔离级别越高,数据越安全,但性能越低

总结:

事务简介:一组操作的集合,这组操作要么全部执行成功,要么全部执行失败

开启事务:start transcaction

提交/回滚事务:commit/rollback

事务四大特性:原子性、一致性、隔离性、持久性

并发事务问题:脏读、不可重复度、幻读

事务隔离级别:read uncommitted/read committed/repeatable read/serializable

建表:

create table account(name varchar(10),money int);
insert into account values ("zhangsan", 2000), ("lisi", 2000);

脏读演示

在这里插入图片描述

不可重复读演示

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

幻读演示

幻读会抛出主键重复异常:查询时查询不到,但是插入时报告主键重复

(进阶篇)存储引擎

存储引擎:存储数据,建立索引,更新/查询数据等技术的实现方式。存储引擎是基于表的,而不是基于库的(同一个库下的多张表可以有不同的存储引擎),所以存储引擎通常也被称为表类型

show create table account;CREATE TABLE `account` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(10) DEFAULT NULL,`money` int(11) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1

默认的存储引擎是 InnoDB

查看支持的存储引擎:

show engines;
-- 创建表my_myisam,并指定MyISAM存储引擎
create table my_myisam (id int,name varchar(10)
) engine = MyISAM;-- 创建表my_memory,并指定Memory存储引擎
create table my_memory (id int,name varchar(10)
) engine = Memory;

InnoDB

InnoDB 引擎的3大特性(优点):事务、外键、行级锁

  • DML操作遵循ACID模型,支持事务
  • 行级锁,提高并发访问性能
  • 支持外键约束,保证数据的完整性和正确性

innodb_file_per_table

在这里插入图片描述

MyISAM

  • 不支持事务和外键
  • 只支持表锁,不支持行锁
  • 访问速度快

Memory

表数据存放在内存中,只能作为临时表或缓存来使用。支持hash索引(只能进行等值匹配,不能进行范围查找)

在这里插入图片描述

索引

索引(index)是帮助MySQL高效获取数据的有序数据结构。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据, 这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引

select * from user where age = 45;

在这里插入图片描述

索引的缺点:

  • 占用更多的空间
  • 增加了insert update delete的开销

在这里插入图片描述

B 树结构:

在这里插入图片描述

在这里插入图片描述

面试题:为什么InnoDB存储引擎选用B+tree索引结构?

在这里插入图片描述
索引的分类:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
对于这样一条查询语句:

select * from user where name = "Arm";

它会先走二级索引查到id值,然后再用id值从聚集索引中查到row数据,这个过程被称为回表查询

以下的2条SQL语句,哪个执行效率高?

select * from user where id = 10;		-- id是主键
select * from user where name = "Arm";	-- name有索引

答:第一个效率更高,因为它无需回表查询

索引语法

create [unique|fulltext] index index_name on table_name(col_name, ...);		-- 创建索引
show index from table_name;
drop index index_name from table_name;

索引可以关联到多个列(字段):

  • 如果索引关联到单个字段,称之为单列索引
  • 如果索引关联到单个字段,称之为多列索引,或联合索引
    在这里插入图片描述
create index idx_user_name on tb_user(name);
create unique index idx_user_phone on tb_user(phone);
create index idx_user_pro_age_stu on tb_user(profession, age, status);
create index idx_user_email on tb_user(email);drop index idx_user_email from tb_user;

SQL性能分析

查看执行频次

查看当前数据库的操作是以“增删改”等 DML 语句为主,还是以查询 DQL 语句为主。如果主要是 DQL,可以考虑建立索引加速查询

mysql> show global status like "Com_______";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Com_binlog    | 0     |
| Com_commit    | 0     |
| Com_delete    | 0     |
| Com_insert    | 0     |
| Com_repair    | 0     |
| Com_revoke    | 0     |
| Com_select    | 125   |
| Com_signal    | 0     |
| Com_update    | 0     |
| Com_xa_end    | 0     |
+---------------+-------+
10 rows in set (0.00 sec)

慢查询日志

记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10s)的所有SQL语句的日志。MySQL的慢查询日志默认没有开启,需要在MySQL的配置文件 /etc/my.cnf 中配置如下信息:

slow_query_log=1
long_query_time=2

show_profiles

select @@have_profiling;		# 查看是否支持profile
select @@profiling;				# 查看profiling是否打开
set profiling=1;				# 打开profiling
show profiles;
show profile for query query_id;
show profile cpu for query query_id;

explain

explain 或者 desc 获取MySQL如何执行 select 语句的信息,包括在select语句执行过程中表如何连接和连接的顺序(sql语句的执行计划)

explain select * from tb1 where cond1;		# 结果的id值越大,越优先执行;如果id相同,从上到下执行

在这里插入图片描述

explain 执行计划各字段含义:

  • id:select 查询的序列号,表示查询中执行 select 子句或操作表的顺序(结果的id值越大,越优先执行;如果id相同,从上到下执行)
  • select_type:simple(简单表,不需要表连接或者子查询)、primary(主查询,即外层的查询)、union(联合查询 union 后面的查询语句)、subquery(子查询)
  • type:连接类型,性能由好到差:NULL、system、const、eq_ref、range、index、all
  • possible_key:可能使用的索引
  • key:实际使用的索引
  • key_len:索引使用的字节数,该值为索引字段最大可能长度
  • rows:MySQL 预估的必须执行查询的行数
  • filtered:返回结果行数占需要读取行数的百分比,值越大越好

最左前缀法则

例如对于联合索引 idx_user_profession_age_status

在这里插入图片描述

在这里插入图片描述

最左索引存在即可,与顺序无关(会自动调整),比如下面的 sql,索引长度仍然是 54(全部索引):

select * from tb_user where status = "0" and age = 31 and profession = "软件工程"

在联合查询中,如果出现范围查询 <>,范围查询右侧的列索引失效

尽量使用 >=<=,这样索引不会失效

select * from tb_user where profession = "SE" and age > 30 and status = '0';		# status失效
select * from tb_user where profession = "SE" and age >= 30 and status = '0';		# status正常

索引失效

不要在索引列上进行运算操作,否则索引将会失效

select * from tb_user where phone = "19858190715";		# 索引有效
select * from tb_user where substring(phone, 10, 2) = "15";		# 索引失效

字符串不加引号,索引会失效(隐式类型转换)

select * from tb_user where phone = 19858190715;		# 索引失效
select * from tb_user where profession = "SE" and age = 30 and status = 0; 	# status索引失效

如果仅在尾部进行模糊匹配,索引不会失效。如果是在头部进行模糊匹配,索引将会失效

select * from tb_user where profession like "软件%";		# 索引有效
select * from tb_user where profession like "%工程";		# 索引失效
select * from tb_user where profession like "%工%";		 # 索引失效

对于or连接的条件,如果一侧有索引,另一侧没有索引,则全部索引失效

select * from tb_user where phone = "19858190715" or age = 23;		# 索引失效
select * from tb_user where id = 10 or age = 23;					# 索引失效

数据分布对索引的影响:如果MySQL评估使用索引比全表扫描还慢,则不使用索引(如结果集就是全表数据)

select * from tb_user where id >= 1;					# 直接全表,不走索引
select * from tb_user where profession is not null;		  # 直接全表,不走索引

SQL提示

在SQL语句中加入一些人为的提示来达到优化的操作目的(同时存在联合索引和单列索引时指定使用单列索引

# use index
select * from tb_user use index(idx_user_pro) where profession = "SE";# ignore index
select * from tb_user ignore index(idx_user_pro) where profession = "SE";# force index
select * from tb_user force index(idx_user_pro) where profession = "SE";

覆盖索引

explain 返回的 Extra 的 2 种情况:

  • using index condition:查询使用了索引,但是需要回表查询数据(低效)
  • using where; using index:查询使用了索引,但是需要的数据在索引列中都能直接找到,所以不需要回表查询数据(高效)
select id, profession, age, status from tb_user where profession = "SE" and age = 31 and status = '0';-- name 字段必须通过回表查询才能得到
select id, profession, age, status, name from tb_user where profession = "SE" and age = 31 and status = '0';--  一般会引发回表查询
select * from tb_user where profession = "SE" and age = 31 and status = "0";

在这里插入图片描述

为什么不推荐 select *:极易产生回表查询

练习题:下面哪条SQL语句会产生回表查询?

select * from tb_user where id = 2;
select id, name from tb_user where name = "Arm";
select * from tb_user where name = "Arm";		# 这条语句会产生回表查询,性能低

一张表,有4个字段(id username password status),由于数据量大,需要对以下SQL语句进行优化,该如何进行?

select id, username, password from tb_user where username = "itcast";

答:对username password建立联合索引,避免回表查询(username 加速查询;passwrod 避免回表)

前缀索引

在保证选择性的前提下,取很长的字符串的一部分建立索引

在这里插入图片描述

create index idx_user_email_5 on tb_user(email(5));

在这里插入图片描述

通过前缀索引获取到数据后需要再检查是否满足where条件

在业务场景中,如果存在多个查询条件,考虑针对查询字段建立索引时,建议建立联合索引,而非单列索引

select id, phone, name from tb_user where phone = "19888876539" and name = "daniel";create unique index idx_user_phone_name on tb_user(phone, name);
select id, phone, name from tb_user use index(idx_user_phone_name) where phone = "19888876539" and name = "daniel";	# 建立联合索引后,不再需要回表查询

联合索引的B+树结构:

在这里插入图片描述

每个节点有2个键值数据

在这里插入图片描述

索引失效情景:

  • 不遵循“最左前缀法则”
  • 在索引列上进行函数运算
  • 字符串不加引号
  • like模糊匹配,% 在前面
  • or连接的条件,一侧有索引,另一侧没有索引,索引失效
  • MySQL评估,走全表扫描比走索引还快,索引失效(数据分布的影响)

SQL优化

insert优化

  • 使用批量插入

  • 手动提交事务

    • start transaction;
      insert into tb_test values(1, "tom"), (2, "cat"), (3, "jerry");
      insert into tb_test values(4, "tom"), (5, "cat"), (6, "jerry");
      insert into tb_test values(7, "tom"), (8, "cat"), (9, "jerry");
      commit;
      
  • 主键顺序插入

  • 如果一次性插入大量数据,使用 insert 插入性能低,此时可以使用 load 指令进行插入

    • mysql --local-infile -uroot -ppswd	# 连接数据库时加入--local-infile选项
      set global local_infile = 1;
      load data local infile "/root/sql1.log" into table "tb_user" fields terminated by "," lines terminated by "\n";
      

主键优化

在这里插入图片描述

根据叶子节点的有序性,主键应顺序插入;如果主键乱序插入,会产生页分裂现象,浪费了时间

在这里插入图片描述

当删除一行记录时,并不会进行物理删除,而只会进行标记。当删除的记录达到 50% 时,会进行页合并以节省空间

在这里插入图片描述
主键设计原则:

  • 尽量降低主键长度
  • 插入数据时尽量选择顺序插入,选择使用 AUTO_INCREMENT 自增主键
  • 尽量不要使用UUID做主键或其他自然主键
  • 业务操作时,尽量避免对主键的修改

order by优化

mysql 有 2 种排序方式:

  • using index:排序过程直接通过有序索引直接返回数据,效率高
  • using filesort:需要将返回的结果在排序缓冲区中排序,所有不是通过索引直接返回排序结果的排序都称为 filesort 排序
-- age 和 phone 没有索引
select id, age, phone from tb_user order by age;		-- using filesort
select id, age, phone from tb_user order by age, phone;		-- using filesortcreate index idx_user_id_age on tb_user(age, phone);
select id, age, phone from tb_user order by age;		-- using index
select id, age, phone from tb_user order by age, phone;		-- using index
select id, age, phone from tb_user order by age desc, phone desc;		-- backward index scan; using index
select id, age, phone from tb_user order by phone, age;		-- using index; using filesort
select id, age, phone from tb_user order by age asc, phone desc;		-- using index; using filesort-- 建立排序方式不同的索引
create index idx_user_id_age_ad on tb_user(age asc, phone desc);
select id, age, phone from tb_user order by age asc, phone desc;		-- using index

在这里插入图片描述

order by优化:

  • 根据排序字段建立适当的索引,多字段排序时也遵循最左前缀法则
  • 尽量使用覆盖索引
  • 多字段排序,一个升序一个降序,需要注意联合索引在创建时的规则(一个升序一个降序)
  • 如果不可变地出现filesort,大数据量排序时,可以适当增大排序缓冲区大小sort_buffer_size

group by优化

select profession, count(*) from tb_user group by profession;	-- using temporarycreate index idx_user_pro_age_sta on tb_user(profession, age, status);	-- 创建联合索引
select profession, count(*) from tb_user group by profession;	-- using index
select profession, count(*) from tb_user group by age;			-- using index; using temporary
select profession, count(*) from tb_user group by profession, age;	-- using index
select profession, count(*) from tb_user where profession = "SE" group by age;	-- using index

在分组操作时,可以通过索引来提高效率

在分组操作时,索引的使用也是满足最左前缀法则

limit优化

select * from tb_sku limit 10, 10;		-- 0s
select * from tb_sku limit 1000000, 10; 	-- 3s
select * from tb_sku limit 5000000, 10; 	-- 11s

limit 的查询时间随着 offset 的增大而增大。因为它需要将前面的所有数据都排序,仅返回少量数据

使用覆盖索引 + 多表联查(子查询)进行优化:

select s.* from tb_sku as s, (select id from tb_sku order by id limit 9000000, 10) as a where s.id = a.id;

count优化

在这里插入图片描述

count的几种用法:

-- count(*) count(pk) count(字段) count(1)
select count(1) from tb_user;	-- 24

在这里插入图片描述

update优化

核心:尽量根据主键/索引字段进行数据更新,避免行锁升级为表锁

对于这样一张表:

create table course (id int primary key auto_increment,name varchar(10)
);insert into course (id, name)
values (1, "Java"),(2, "PHP"),(3, "MySQL"),(4, "Hadoop");

InnoDB引擎3大特性:事务,外键,行级锁

行级锁的条件下,下面的两个事务得以成功并发执行:

begin; 	-- transcation1
update course set name = "javaEE" where id = 1;
commit;begin; 	-- transcation2
update course set name = "Kafuka" where id = 4;
commit;

但是如果where条件使用name:

begin; 	-- transcation1
update course set name = "springboot" where name = "PHP";	-- 行锁升级为表锁
commit;begin; 	-- transcation2
update course set name = "Kafka" where id = 4;		-- 等待上一条update提交
commit;

name没有索引,被加了表锁。所以使用update更新数据时要根据索引字段进行更新,解决上面的问题的办法就是为 name 字段建立索引:

create index idx_course_name on course(name);

在这里插入图片描述

小结

在这里插入图片描述

视图

视图(View)是一种虚拟存在的表。视图中的数据并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的。
通俗的讲,视图只保存了查询的SQL逻辑,不保存查询结果。所以我们在创建视图的时候,主要的工作就落在创建这条SQL查询语句上。

-- 创建视图
create [or replace] view view_name[(column_name)] as (select from 基表) [with [cascaded | local] check option];

对于这样一张表:

create table student (id int primary key auto_increment,name varchar(20),no char(10)
);insert into student (id, name, no)
values (1, "daiqisi", "2000100100"),(2, "xiexun", "2000100102"),(3, "yintianzheng", "2000100103"),(4, "weiyixiao", "2000100104");

创建一个视图:

create or replace view stu_v1 as (select id, name from student where id <= 10);
-- 查看创建视图的语句
show create view view_name;
-- 查看视图数据
select * from view_name;

查询视图:

select * from stu_v1 where id < 3;

修改视图:

create or replace view view_name[(column_name)] as (select from 基表) [with [cascaded | local] check option];
alter view view_name[(column_name)] as (select from 基表) [with [cascaded | local] check option];alter view stu_v1 as select id, name from student where id <= 10;

删除视图:

drop view if exists view_name;

检查选项

drop view if exists  stu_v1;
create or replace view  stu_v1 as select id, name from student where id <= 20;select * from stu_v1;insert into stu_v1 values(6, "Tom");    -- 插到了基表
insert into stu_v1 values(30, "Tom");   -- 插入了基表,但是在本视图查不到

为了避免出现上面这种基表和视图数据不一致的情况,增加检查选项

cascaded

create or replace view  stu_v1 as select id, name from student where id <= 20 with cascaded check option;select * from stu_v1;insert into stu_v1 values(6, "Tom");    -- 插到了基表
insert into stu_v1 values(30, "Tom");   -- 插入失败

视图可以基于视图创建,对于级联的 check option,不仅会检查当前的 check option,还会检查上一级视图的 check option

在这里插入图片描述

local

create or replace view  stu_v4 as select id, name from student where id <= 15;insert into stu_v4 values(6, "Tom");    -- 成功
insert into stu_v4 values(16, "Tom");   -- 成功create or replace view  stu_v5 as select id, name from stu_v4 where id >= 10 with local check option;
insert into stu_v5 values(13, "Tom");   -- 成功
insert into stu_v5 values(17, "Tom");   -- 成功,因为 stu_v4 没有定义 local check option.如果是 cascaded 则不会成功create or replace view stu_v6 as select id, name from stu_v5 where id < 20;
insert into stu_v6 values(14, "Tom");   -- 成功

视图更新

只能在视图和基表的行是一对一的关系下才能更新视图

在这里插入图片描述

create view stu_v_count as select count(*) from student;
insert into stu_v_count values(10);     -- The target table stu_v_count of the INSERT is not insertable-into

视图的作用:

  • 简单:视图不仅可以简化用户对数据的理解,也可以简化他们的操作那些被经常使用的查询可以被定义为视图,从而使得用户不必为以后的操作每次指定全部的条件
  • 安全:通过视图用户只能查询和修改他们所能见到的数据数据库可以授权,但不能授权到数据库特定行和特定的列上
  • 数据独立:视图可帮助用户屏蔽真实表结构变化带来的影响

视图案例

根据如下需求,定义视图:

  1. 为了保证数据库表的安全性,开发人员在操作 tb_user 表时,只能看到的用户的基本字段,屏蔽手机号和邮箱两个字段
  2. 查询每个学生所选修的课程(三张表联查),这个功能在很多的业务中都有使用到,为了简化操作,定义一个视图
create view tb_user_v1 as select id, name, profession, age, gender, status, createtime from tb_user;
select * from tb_user_v1;create view tb_student_course_v1 asselect s.name as student_name,s.no as studnet_no,c.name as course_namefromstudent as s,student_course as sc,course as cwheres.id = sc.studnetid and c.id = sc.courseid;

存储过程

存储过程是事先经过编译并存储在数据库中的一段 SQL 语句的集合,调用存储过程可以简化应用开发人员的很多工作,减少数据在数据库和应用服务器之间的传输,对于提高数据处理的效率是有好处的。存储过程思想上很简单,就是数据库 SQL 语言层面的代码封装与重用

特点:

  • 封装,复用
  • 可以接受参数,也可以返回数据
  • 减少网络交互,效率提升
create procedure p1()
beginselect count(*) from student;
end;call p1();select * from information_schema.ROUTINES where ROUTINE_SCHEMA = "itcast";
show create procedure p1;drop procedure if exists p1;

在命令行中,执行创建存储过程的 SQL 时,需要通过关键字 delimiter 指定 SQL 语句的结束符(在 datagrip 则没有这个问题)

delimiter $$

变量

系统变量

在这里插入图片描述
查看系统变量:

show variables;
show session variables;show session variables like 'auto%';select @@autocommit;    -- 查看特定系统变量的值
select @@global.autocommit;

设置系统变量:

set session autocommit = 0;
select @@session.autocommit;

如果没有指定 SESSION/GLOBAL,默认是 SESSION

mysqld 重启后,全局参数会失效,若不想失效可以在 /etc/my.cnf 配置

用户自定义变量

在这里插入图片描述

set @myname = 'itcast';     -- 无需提前声明
set @myage := 10;
select count(*) into @mycnt from student;select @myname, @myage, @mycnt;

局部变量

在这里插入图片描述

create procedure p2()
begindeclare stu_count int default 0;select count(*) into stu_count from student;select stu_count;
end;call p2();

if

if c1 then...
elseif c2 then...
else...
end if;
create procedure p3()
begindeclare score int default 58;declare result varchar(10);if score >= 85 thenset result := 'great';elseif score >= 60 thenset result := 'pass';elseset result := 'failure';end if;select result;
end;call p3();

参数

在这里插入图片描述

create procedure p4(in score int, out result varchar(10))
beginif score >= 85 thenset result := 'great';elseif score >= 60 thenset result := 'pass';elseset result := 'failure';end if;
end;call p4(90, @result);
select @result;-- 将 200 分制的分数转化为百分制并返回
create procedure p5(inout score double)
beginset score := score / 2;
end;set @score = 180;
call p5(@score);
select @score;  -- 90

case

在这里插入图片描述

create procedure p6(in month int)
begindeclare result varchar(10);casewhen month >= 1 and month <= 3 thenset result := '1';when month >= 4 and month <= 6 thenset result := '2';when month >= 7 and month <= 9 thenset result := '3';when month >= 10 and month <= 12 thenset result := '4';elseset result := 'invalid';end case;select concat(month, ': ', result);
end;call p6(8);

while

在这里插入图片描述

create procedure p7(in n int)
begindeclare total int default 0;while n > 0 doset total := total + n;set n := n - 1;end while;select total;
end;call p7(10);

repeat

在这里插入图片描述

create procedure p8(in n int)
begindeclare total int default 0;repeatset total := total + n;set n := n - 1;until  n <= 0 end repeat;select total;
end;call p8(100);

loop

在这里插入图片描述
求从 1 ~ n 的和:

create procedure p9(in n int)
begindeclare total int default 0;sum: loopif n <= 0 thenleave sum;end if;set total := total + n;set n := n - 1;end loop;select total;
end;call p9(100);

计算 1 ~ n 之间偶数累加的值:

create procedure p10(in n int)
begindeclare total int default 0;sum: loopif n <= 0 thenleave sum;end if;if n % 2 = 1 thenset n := n - 1;iterate sum;end if;set total := total + n;set n := n - 1;end loop;select total;
end;call p10(100);

cursor

在这里插入图片描述

需求:根据传入的参数 uage,来查询用户表tb_user中,所有的用户年龄小于等于 uage 的用户姓名(name)和专业(profession),并将用户的姓名和专业插入到所创建的一张新表(id,name,profession)中

create procedure p11(in uage int)
begindeclare uname varchar(100);declare upro varchar(100);declare u_cursor cursor for select name, profession from tb_user where age <= uage;drop table if exists tb_user_pro;create table if not exists tb_user_pro(id int primary key auto_increment,name varchar(100),profession varchar(100));open u_cursor;while true dofetch u_cursor into uname, upro;insert into tb_user_pro values (null, uname, upro);end while;close u_cursor;
end;call p11(30);

handler

在这里插入图片描述

declare exit handler for SQLSTATE '02000' close u_cursor;   -- 类似于出错后的中断回调
declare exit handler for not found close u_cursor;   -- 类似于出错后的中断回调
create procedure p11(in uage int)
begindeclare uname varchar(100);declare upro varchar(100);declare u_cursor cursor for select name, profession from tb_user where age <= uage;declare exit handler for SQLSTATE '02000' close u_cursor;   -- 类似于出错后的中断回调-- declare exit handler for not found close u_cursor;   -- 类似于出错后的中断回调drop table if exists tb_user_pro;create table if not exists tb_user_pro(id int primary key auto_increment,name varchar(100),profession varchar(100));open u_cursor;while true dofetch u_cursor into uname, upro;insert into tb_user_pro values (null, uname, upro);end while;close u_cursor;
end;call p11(30);

存储函数

在这里插入图片描述

需求:使用存储函数实现从 1 ~ n 的累计

create function f1(n int)
returns int deterministic
begindeclare total int default 0;while n > 0 doset total := total + n;set n := n - 1;end while;return total;
end;select f1(100);

触发器

在这里插入图片描述

行级触发器和语句级触发器的区别:比如一条 update 语句一次更新 5 行,行级触发器会被触发 5 次,而语句级触发器会被触发 1 次

insert

在这里插入图片描述

需求:通过触发器记录 user 表的数据变更日志(user_logs),包含增加,修改,删除

创建日志表:

create table if not exists user_logs(id int primary key auto_increment,operation varchar(20) not null,operate_time datetime not null,operate_id int not null,operate_params varchar(500)
) default charset=utf8;

插入数据触发器:

create trigger tb_user_insert_trigger after insert on tb_user for each row
begininsert into user_logs(id, operation, operate_time, operate_id, operate_params)values (null, 'insert', now(), new.id, concat('inserted data: id = ', new.id, ', name = ', new.name));
end;

update

create trigger tb_user_update_trigger after update on tb_user for each row
begininsert into user_logs(id, operation, operate_time, operate_id, operate_params)values (null, 'update', now(), new.id, concat('updated data: id = ', new.id, ', name = ', new.name));
end;

delete

create trigger tb_user_delete_trigger after delete on tb_user for each row
begininsert into user_logs(id, operation, operate_time, operate_id, operate_params)values (null, 'delete', now(), old.id, concat('deleted data: id = ', old.id, ', name = ', old.name));
end;

view:

  • 虚拟存在的表,不保存查询结果,只保存查询的 SQL 逻辑
  • 简单,安全,数据独立

procedure:

  • 事先定义并存储在数据库中的一段 SQL 语句的集合
  • 减少网络交互,提高性能,封装重用
  • 变量、if、case、参数(in/out/inout)、while、repeat、loop、cursor、handler

function:

  • 存储函数是有返回值的存储过程,参数类型只能为 IN 类型
  • 存储函数可以被存储过程替代

trigger:

  • 可以在表数据进行 insert、update、delete 之前或之后触发
  • 保证数据完整性、日志记录、数据校验

  • 全局锁:锁住数据库中的所有表
  • 表级锁:每次操作锁住整张表
  • 行级锁:每次操作锁住对应的行数据

全局锁

对整个数据库加锁,加锁后整个库就处于只读状态,后续的 DML语句、DDL 语句、已经更新操作的事务提交语句都将被阻塞

典型的使用场景就是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性

在这里插入图片描述

数据库中加全局锁,是一个比较重的操作,存在以下问题:

  • 如果在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆
  • 如果在从库上备份,那么在备份期间从库不能执行主库同步过来的二进制日志(binlog),会导致主从延迟

在InnoDB引擎中,我们可以在备份时加上参数 --single-transaction 参数来完成不加锁的一致性数据备份:

mysqldump --single-transaction -uroot -p123456 itcast> itcast.sql

表级锁

表级锁,每次操作锁住整张表。锁定粒度大,发生锁冲突的概率最高,并发度最低。应用在MyISAM、InnoDB、BDB等存储引擎中

表级锁主要分为3类:

  • 表锁
  • 元数据锁(meta data lock,MDL)
  • 意向锁

表锁

表锁又可被分为2类:共享读锁&独占写锁

  • read lock(共享)
  • write lock(独占)

语法:

lock tables tb read/write;
unlock tables;

对于读锁,当前客户端和其他客户端都能读,但是都不能写

对于写锁,其他客户端不能读写,当前客户端能够读写

在这里插入图片描述

元数据锁

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

意向锁

如下图,线程 A 根据主键 update id = 3 的数据时,会自动加上行锁。此时如果线程 B 过来加表锁,它需要逐行检查每一行是否添加了行锁,效率很差

为了解决这个问题,引入意向锁:为了避免行锁与表锁之间的冲突,在 InnoDB 中引入了意向锁,使表锁不用检查每行数据是否加锁,使用意向锁来减少表锁的检查

在这里插入图片描述
如果另一个任务试图在该表级别上应用共享或排它锁,则受到由第一个任务控制的表级别意向锁的阻塞。第二个任务在锁定该表前不必检查各个页或行锁,而只需检查表上的意向锁

意向锁不会与行级的共享 / 排他锁互斥

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

行级锁

在这里插入图片描述

行锁

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

如果不通过索引检索数据,InnoDB 会对表中的所有记录加锁,升级为表锁:
在这里插入图片描述

间隙锁

间隙锁可以防止幻读

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

小结

概述:

  • 在并发访问时,解决数据访问的一致性、有效性问题
  • 全局锁、表级锁、行级锁

全局锁:

  • 对整个数据库实例加锁,加锁后整个实例就处于只读状态
  • 性能较差,数据逻辑备份时使用

表级锁:

  • 操作锁住整张表,锁定粒度大,发生锁冲突的概率高
  • 表锁、元数据锁、意向锁

行级锁:

  • 操作锁住对应的行数据,锁定粒度最小,发生锁冲突的概率最低
  • 行锁、间隙锁、临键锁

InnoDB 引擎

逻辑存储结构

在这里插入图片描述

架构

在这里插入图片描述

内存结构

在这里插入图片描述

磁盘结构

在这里插入图片描述

后台线程

将 InnoDB 缓存中存在的数据在合适的时机刷新到磁盘当中

在这里插入图片描述

事务原理

在这里插入图片描述

redo log

用于刷新脏页到磁盘发生错误时,进行数据恢复使用
在这里插入图片描述

刷新 redo log file 要比刷新 ibd 文件快得多,因为前者是随机磁盘 IO,后者是顺序磁盘 IO,性能更高

2个 redo log 是循环写的,并不会永久保留下来,占用空间不大

undo log

undo log 主要用于实现事务的原子性

回滚日志,用于记录数据被修改前的信息,作用含两个:提供回滚 和 MVCC(多版本并发控制)

undo log 和 redo log记录物理日志不一样,它是逻辑日志。可以认为当 delete 一条记录时,undo log 中会记录一条对应的 insert 记录,反之亦然。当 update 一条记录时,它记录一条对应相反的 update 记录。当执行 rollback 时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚
undo log 销毁:undo log 在事务执行时产生,事务提交时,并不会立即删除 undo log,因为这些日志可能还用于MVCC
undo log 存储:undo log 采用的方式进行管理和记录,存放在前面介绍的 rollback segment 回滚段中,内部包含 1024 个 undo log segment

MVCC

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

隐式字段

在这里插入图片描述

undo log

回滚日志,在 insert、update、delete 的时候产生的便于数据回滚的日志

当 insert 的时候,产生的 undo log 日志只在回滚时需要,在事务提交后,可被立即删除

而 update、delete 的时候,产生的 undo log 日志不仅在回滚时需要,在快照读时也需要,不会立即被删除

对于这样一条记录:

在这里插入图片描述
其版本链如下:

在这里插入图片描述

read view

在这里插入图片描述

在这里插入图片描述

RC 级别分析

下图说明了事务 5 的第二个查询在 MVCC 版本链上匹配的过程,通过直接观察可以看出,事务 5 的第二次读取,能够读取到事务 3 提交的记录

首先匹配表中的记录,事务 ID 为 4,所有规则均不成立

接着匹配 undo log 版本链上的第一条数据,事务 ID 为3,满足第二条匹配规则:记录的事务 ID 小于当前活跃的最小事务 ID,说明该事务已经提交,可以读取

在这里插入图片描述

RR 级别分析

在这里插入图片描述

小结

逻辑存储结构:表空间、段、区、页、行

架构:内存结构&磁盘结构

MVCC:

  • 记录隐藏字段
  • undo log 版本链
  • readView

MySQL 管理

在这里插入图片描述

常用工具:

在这里插入图片描述

mysql:客户端工具,-e 执行 SQL 并退出

mysqladmin:MySQL 管理工具

mysqlbinlog:二进制查看工具

mysqlshow:查看数据库,表,字段的统计信息

mysqldump:数据备份工具

mysqlimport/source:数据导入工具

(运维篇)日志

错误日志

错误日志是 MySOL 中最重要的日志之一,它记录了当 mysqld 启动和停止时,以及服务器在运行过程中发生任何严重错误时的相关信息

当数据库出现任何故障导致无法正常使用时,建议首先查看此日志

该日志是默认开启的,默认存放目录 /var/log/,默认的日志文件名为 mysqld.log

通过如下命令查看错误日志位置:

show variables like '%log_error%';

查看错误日志:

tail -f /var/log/mysqld.log

二进制日志

binlog 记录了所有 DDL 和 DML 语句,但不包括查询语句

作用:

  • 灾难时的数据恢复
  • MySQL 的主从复制
show variables like '%log_bin%';

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

查询日志(所有日志)

查询日志中记录了客户端的所有操作语句,而二进制日志不包含查询数据的SQL语句。默认情况下,查询日志是未开启的

show variables like '%general%';

打开该选项:

// /etc/my.cnf
general_log=1
general_log_file=/var/lib/mysql/mysql_query.log

慢查询日志

在这里插入图片描述

主从复制

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

主库配置

首先关闭主机和从机的防火墙

在这里插入图片描述

从库配置

在这里插入图片描述

分库分表

在这里插入图片描述

拆分策略

垂直拆分:

  • 垂直分库:根据业务将不同的表拆分到不同的库中
  • 垂直分表:根据字段属性将不同的字段拆分到不同的表中(例如将占用空间较大而又不重要的字段拆分出去)

水平拆分:

  • 水平分库:对库中的每个表做水平拆分
  • 水平分表:将表按照水平方向“剪开”,每张表的结构都一样

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

MyCat

Mycat:数据库分库分表中间件,不用调整代码即可实现分库分表,支持多种语言

相关文章:

黑马数据库学习笔记

课程地址 &#xff08;基础篇&#xff09;MySQL的启动 mysql 默认使用 3306 端口 在 centos下&#xff0c;启动 mysql 数据库&#xff1a;service mysqld start; 查看状态/启动/停止/重启&#xff1a;systemctl status/start/stop/restart mysqld; 登录到mysql数据库&…...

MYSQL-SQL-03-DQL(Data Query Language,数据查询语言)(单表查询)

DQL&#xff08;数据查询语言&#xff09; DQL英文全称是Data Query Language(数据查询语言)&#xff0c;数据查询语言&#xff0c;用来查询数据库中表的记录。 查询关键字: SELECT 在一个正常的业务系统中&#xff0c;查询操作的频次是要远高于增删改的&#xff0c;当我们去访…...

【数据结构和算法】三、动态规划原理讲解与实战演练

目录 1、什么是动态规划&#xff1f; 2、动态规划实战演练 2.1 力扣题之爬楼梯问题 &#xff08;1&#xff09;解题思路1: &#xff08;2&#xff09;解题思路2: &#xff08;3&#xff09;动态规划&#xff08;DP&#xff09;&#xff1a;解题思路 &#xff08;4&#x…...

交叉编译 perl-5.40.0(riscv64)

交叉编译 perl-5.40.0&#xff08;riscv64&#xff09; https://arsv.github.io/perl-cross/usage.html https://github.com/arsv/perl-cross 借助 perl-cross 进行交叉编译 https://www.perl.org/get.html#unix_like 这里获取 perl-5.40.0 的源码 https://github.com/arsv/pe…...

Leetcode 搜索旋转排序数组

这段代码是用于解决LeetCode第33题“搜索旋转排序数组”的Java解法。以下是对该算法思想的中文解释&#xff1a; 算法思想 二分查找的基本思路&#xff1a; 由于数组是部分有序的&#xff08;被旋转过&#xff09;&#xff0c;我们可以利用二分查找的思想&#xff0c;逐步缩小…...

Spring Task—定时任务

Spring Task 是 Spring 提供的一种轻量级定时任务调度功能&#xff0c;内置在 Spring 框架中。与 Quartz 等重量级调度框架相比&#xff0c;Spring Task 使用简便&#xff0c;无需额外依赖&#xff0c;适合在简单的调度任务场景中使用。通过注解配置方式&#xff0c;开发者可以…...

Spring Boot 应用开发概述

目录 Spring Boot 应用开发概述 Spring Boot 的核心特性 Spring Boot 的开发模式 Spring Boot 在企业应用开发中的优势 结论 Spring Boot 应用开发概述 Spring Boot 是由 Pivotal 团队开发的一个框架&#xff0c;基于 Spring 框架&#xff0c;旨在简化和加速基于 Spring …...

Chrome谷歌浏览器加载ActiveX控件之allWebDesktop控件介绍

背景 allWebDesktop控件是一款方便用户在线打开各类文档的OA办公控件。它设计比较轻巧&#xff0c;充分利用计算机程序资源打开文档&#xff0c;并将程序窗口嵌入到allWebDesktop控件区域内&#xff0c;从而实现浏览器内打开各类文档效果。 allWebPlugin中间件是一款为用户提供…...

GitHub Star 数量前 5 的开源应用程序生成器

欢迎来的 GitHub Star 数量排名系列文章的第 7 篇——最受欢迎的应用程序生成器。 之前我们已经详细探讨过&#xff1a;在 GitHub 上最受欢迎的——无代码工具、低代码项目、内部工具、CRUD项目、自部署项目和 Airtable 开源替代品。累计超过 50 个优质项目&#xff01;&#…...

DBC文件当中新建CANFD等类型的报文

同学最近有添加CANFD报文的需求&#xff0c;需要用到CANFD类型报文的DBC文件&#xff0c;这下就难住我了&#xff0c;我之前用的DBC文件只有“CAN Standard”“CAN Extended”两种类型&#xff0c;压根没见过FD的。 后来他找到了项目之前的DBC&#xff0c;打开来看&#xff0c…...

基于SpringBoot的房地产销售管理系统【附源码】

基于SpringBoot的房地产销售管理系统&#xff08;源码L文说明文档&#xff09; 目录 4 系统设计 4.1用户登录功能的详细实现 4.2管理员权限的功能实现 4.2.1客户信息管理功能的详细实现 4.2.2房产管理功能的详细实现 4.2.3预约看房功能的详细实现 4.2.4论…...

圆点虚线 Android

参考 https://blog.csdn.net/l_o_s/article/details/73550876 <com.xxx.wwww.weight.PointDividerViewandroid:layout_width"match_parent"android:layout_height"wrap_content"app:PDbackgroundColor"color/white"app:dotColor"color/…...

贵州鑫宏远农业-始终致力于推动现代农业的科技创新与发展

贵州鑫宏远农业科技有限公司&#xff0c;是一家在高科技农业领域深耕细作、锐意进取的企业。自成立以来&#xff0c;我们始终致力于推动现代农业的科技创新与发展&#xff0c;业务全面覆盖农业科学研发、组织培养生产、专业育苗培植、半成品及成品精细化养护、市场销售以及全方…...

程序员做销售,从代码到客户的逆袭之路

大家好&#xff0c;我是小悟。 在这个互联网风起云涌、技术迭代日新月异的时代&#xff0c;“跨界”已然成为一种新潮流。就好似那从天而降的大侠&#xff0c;一不小心就可能横跨了数个充满奇遇与挑战的领域。 想象一下&#xff0c;一个平日里只跟代码打交道的程序员&#xf…...

Flink CDC系列之:理解学习Kubernetes模式

Flink CDC系列之&#xff1a;理解学习Kubernetes模式 准备会话模式启动会话集群设置 Flink CDC提交 Flink CDC Job Kubernetes 是一种流行的容器编排系统&#xff0c;用于自动化计算机应用程序的部署、扩展和管理。Flink 的原生 Kubernetes 集成允许您直接在正在运行的 Kuberne…...

git合并相关操作详解

在使用Git进行分支管理时,合并(merge)操作是非常常见的。下面是Git合并相关的详细步骤和一些常见的场景及注意事项。 一、 基本合并操作 假设我们有两个分支:main 和 feature,希望将 feature 合并到 main 上。 切换到目标分支 首先需要切换到你想合并到的分支。例如,切…...

前端经典【面试题】持续更新HTML、CSS、JS、VUE、FLUTTER、性能优化等

HTML/CSS 面试题 什么是语义化 HTML&#xff1f; 说明&#xff1a;语义化 HTML 使用 HTML 标签来描述内容的含义&#xff0c;而不仅仅是其外观。使用语义化标签可以提高可读性和可访问性&#xff0c;并对 SEO 友好。示例&#xff1a; <header><h1>网站标题</h1&…...

【Linux知识】linux磁盘管理深入了解

文章目录 常见磁盘管理命令行磁盘分区NASNAS 磁盘挂载&#x1f510; 如何设置NAS设备的访问权限&#xff1f; Mkfs&#x1f9d0; mkfs 命令支持哪些文件系统类型&#xff1f; Mount&#x1f511; 在Linux中&#xff0c;如何安全地卸载挂载的文件系统&#xff1f; 常见磁盘管理命…...

Qt Essential Classes

目录 QVariant QFlags QRandomGenerator 经典的Qt容器 QVector QList QMap QMultiMap QSet QHash QVariant 同std::variant是一样的&#xff0c;他是一个更加高级的union。在一个时间下&#xff0c;它虽然实际上只能是一种类型&#xff0c;但是一个variant可以hold住…...

小小猫棒onu替换家用光猫,薅运营商带宽羊毛,突破1000M

小小猫棒onu 一、总体步骤 1 记录原来光猫信息 主要包括SN&#xff0c;ploam密码&#xff0c;loid、loid密码、 mac、上网的vlan id等 一般gpon采用SN、ploam密码、SNploam密码三种中的一种认证方式 一般Epon采用loid&#xff08;逻辑id&#xff09;、mac、loid mac三种中…...

软件测试学习笔记丨Selenium学习笔记:css定位

本文转自测试人社区&#xff0c;原文链接&#xff1a;https://ceshiren.com/t/topic/22511 本文为霍格沃兹测试开发学社的学习经历分享&#xff0c;写出来分享给大家&#xff0c;希望有志同道合的小伙伴可以一起交流技术&#xff0c;一起进步~ 说明&#xff1a;本篇博客基于sel…...

python数据处理常用操作

数据处理是机器学习中非常重要的一步&#xff0c;以下是一些常用的操作和示例代码&#xff1a; 1. 数据清洗 处理缺失值&#xff1a; import pandas as pd# 读取数据 df pd.read_csv(data.csv)# 删除缺失值 df.dropna(inplaceTrue)# 用均值填充缺失值 df.fillna(df.mean(), i…...

解决minio跨域问题

MinIO 支持跨域资源共享(CORS)&#xff0c;允许你配置跨域请求的相关策略。以下是一个基本的CORS配置示例&#xff0c;你可以在MinIO的配置文件&#xff08;例如config.json&#xff09;中设置这些策略&#xff1a; 在Linux中 root/.minio 目录下如果没有就新建一个 config.jso…...

python 跳过当前循环

在 Python 中&#xff0c;可以使用 continue 语句来跳过当前循环的剩余部分&#xff0c;并继续下一次循环。continue 语句用于跳过循环体中剩余的语句&#xff0c;并立即开始下一次迭代。 以下是一个简单的示例&#xff0c;演示了如何在 for 循环中使用 continue 语句&#xf…...

数据库数据恢复—Oracle ASM磁盘组掉线 ,ASM实例无法挂载的数据恢复案例

Oracle数据库数据恢复环境&故障&#xff1a; Oracle ASM磁盘组由4块磁盘组成。Oracle ASM磁盘组掉线 &#xff0c;ASM实例不能mount。 Oracle数据库故障分析&恢复方案&#xff1a; 数据库数据恢复工程师对组成ASM磁盘组的磁盘进行分析。对ASM元数据进行分析发现ASM存储…...

jupyter notebook改变默认启动路径

安装好Anaconda 3以后&#xff0c;就可以使用Jupyter notebook了&#xff0c;但是我们打开Jupyter notebook后&#xff0c;发现界面是一个默认的目录&#xff0c;这个目录在哪里&#xff1f;如果想把自己写的程序文件保存在自己新建的一个文件夹里&#xff0c;修改默认目录到自…...

libevent源码剖析-基本数据结构

1 简介 前面系列文章对libevent源码的主体结构&#xff0c;从reactor框架实现&#xff0c;到evbuffer和bufferevent实现原理&#xff0c;及libevent的例子进行了剖析&#xff0c;自此&#xff0c;我们便可基于libevent开发app了。 从本文开始&#xff0c;主要来介绍下libevent源…...

往期文章汇总——射频测量+无线通信+软件无线电+6G科普

本节目录 一、射频测量系列往期链接 二、无线通信系列往期链接 三、软件无线电系列往期链接 四、6G科普系列往期链接本节内容 一、射频测量系列往期链接 射频测量 | 滤波器的关注指标 射频测量 | 射频电路中的负载与滤波器 射频测量 | 射频衰减器的功率系数 射频测量 | 衰减…...

微信小程序 - 深 / 浅拷贝实现方法,微信小程序深拷贝与浅拷贝,函数方法封装直接调用使用,深拷贝cloneDeep和浅拷贝clone(深复制和浅复制)

前言 在微信小程序中,你无法 直接使用常规浏览器环境中的深浅拷贝方法。 但可以借助 utils.js 实现,下面是方法。 创建深浅拷贝函数 依次打开小程序目录【utils】→【utils.js】,写入深拷贝函数并暴露出去。 // utils.js// 对象深拷贝函数 const deepClone = function(in…...

Log4Net配置详解及输出自定义消息类示例代码

1.简单使用实例 1.1 添加log4net.dll的引用。 在NuGet程序包中搜索log4net并添加&#xff0c;此次我所用版本为2.0.17。如下图&#xff1a; 1.2 添加配置文件 右键项目&#xff0c;添加新建项&#xff0c;搜索选择应用程序配置文件&#xff0c;命名为log4net.config&#xff0c…...

网站开发实战项目/学开网店哪个培训机构好正规

概述 Floodlight内部定义报文格式的代码位于net.floodlightcontroller.packet&#xff0c;其中定义的报文类型有ARP,BPDU,BSN,BSNPROBE,DHCP,Ethernet,ICMP,IPv4&#xff0c;LLC,LLDP,TCP,UDP。 其中定义了一个名为IPacket的接口&#xff0c;该接口结构如图&#xff1a; 包…...

如何将vs做的网站备份出来6/软文之家

我做了一個傻事&#xff0c;要在Server上新增一張網卡&#xff0c;可是因為一直無法啟動&#xff0c; 所以很自然的以為CentOS 6又多了其他的設定要求&#xff0c; 因此查了兩天的資料&#xff0c;也試過很多方式&#xff0c;但都沒有效用。 今天早上心血來潮&#xff0c;想說用…...

导航栏宽度wordpress/做网站要多少钱

来源&#xff1a;Modis数据简介 - zerobyzero - 博客园 (cnblogs.com) 【ENVI精讲】处理专题十二&#xff1a;基于MODIS数据的气溶胶遥感监测 - 知乎 (zhihu.com) MODIS 二级气溶胶产品指北&#xff08;with Python&#xff09; - 炸鸡人博客 (zhajiman.github.io) 美国于19…...

商城网站有什么好处/关键词优化推广公司哪家好

在上一篇我们对Docker做了一个简单介绍&#xff0c;有了一个犹抱琵琶半遮面的认识&#xff0c;这篇文章就揭开这半面黑纱&#xff0c;让Docker安装在我们的电脑上&#xff0c;根据官方文档&#xff0c;我们去操作它&#xff0c;去驾驭它&#xff01;我的电脑是Mac&#xff0c;可…...

沂源网站开发/上海推广服务

&#xff08;1&#xff09;第一个程序“”“Hello World” 实现python环境打印输出&#xff1a;Hello World 程序&#xff1a; print("Hello World") 数据类型转换 数据类型&#xff1a;int整形&#xff0c;str字符型&#xff0c;不同类性的数据不能相加、减。 正确&…...

做的比较炫的网站/域名免费注册0元注册

转载于:https://blog.51cto.com/13956693/2173332...