文章目录
数据库
关系型数据库 (RDBMS)
- 关系型数据库管理系统 (Relational Database Management System, RDBMS) 是一种基于关系模型的数据库管理系统,它采用表格的形式存储数据,并使用 SQL (Structured Query Language) 等标准语言进行数据的管理和操作。
- 关系模型是用二维表格的形式来表示数据之间的逻辑关系,其中每张表代表一个实体,每行记录代表一个实例,每列代表一个属性。不同表之间可以通过共享某些属性(通常是主键和外键)来建立关系,从而实现对数据的高效检索和处理。
- 与其他非关系型数据库相比,关系型数据库具有数据结构明确、易于理解和维护、数据一致性好等优点。它们通常支持事务处理、完整性约束、安全控制等高级特性,适合存储复杂的事务性数据。
- 目前市面上广泛使用的关系型数据库包括 Oracle、MySQL、Microsoft SQL Server、IBM DB2、PostgreSQL 等,它们都支持 SQL 作为标准接口,使得开发人员能够使用统一的语言对数据进行操作。
非关系型数据库 (NoSQL)
- 非关系型数据库(NoSQL)是一种相对于传统关系型数据库而言的数据库模型,其名称“NoSQL”源自“Not Only SQL”的缩写,即不仅仅是关系型数据库。
- 与传统关系型数据库的二维表形式存储数据不同,NoSQL 数据库采用文档、键值、图形或列族等非关系型结构来存储数据。NoSQL 数据库具有分布式、可扩展、高可用、高性能等优点,在大规模数据存储和处理场景下尤其突出。
- NoSQL 数据库最早是由 Google 在 2004 年左右开发的 Bigtable 和 Amazon 在 2007 年左右开发的 DynamoDB 等应用所推动的。近年来,随着云计算、大数据和物联网等技术的兴起,NoSQL 数据库在互联网企业、社交网络、电子商务、移动应用等领域被广泛应用。
- 不同类型的 NoSQL 数据库适用于不同的场景,常见的 NoSQL 数据库包括:
- 文档数据库(Document Database):例如 MongoDB,适用于存储半结构化数据。
- 键值数据库(Key-value Database):例如 Redis,适用于高速读写场景。
- 列族数据库(Column-family Database):例如 HBase,适用于高吞吐量数据存储场景。
- 图形数据库(Graph Database):例如 Neo4j,适用于图数据存储和处理场景。
MySQL
MySQL相关介绍
语法规范
- 不区分大小写:建议关键字大写,表名列名小写
- 每条命令使用“;”结尾
- 根据需要,合理使用缩进或换行
- 注释
单行注释:#注释文字
单行注释:-- 注释文字 – 后面一定要加空格
多行注释:/* 注释文字 */ - 各子句一般分行写,关键字不能缩写也不能分行
MySQL安装
- 属于c/s架构的软件,一般来讲安装服务端
- 安装路径不要包含中文或者空格等特殊字符(使用纯英文目录)
方式一:解压配置方式
下载链接:https://downloads.mysql.com/archives/community/
在解压目录创建my.ini文件并添加内容
[mysqld]
# 设置3306端口
port=3306
character-set-server=utf8
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB
[mysql]
# 设置mysql客户端默认字符集
default-character-set=utf8
[client]
#设置mysql客户端连接服务端时默认使用的端口
port=3306
default-character-set=utf8
方式二:步骤安装方式
下载链接:https://downloads.mysql.com/archives/installer/
MySQL卸载
MySQL服务的启动和停止
方式一:计算机——右击管理——服务——MySQL
方式二:通过管理员身份运行cmd命令提示行
net start mysql(服务名)(启动服务)
net stop mysql(服务名)(停止服务)
MySQL服务的登录和退出
方式一:通过MySQL自带的客户端,只限于root用户
方式二:通过windows自带的客户端
登录:
mysql 【-h主机名 -P端口号 】-u用户名 -p密码
例:mysql -h localhost -P 3306 -u root -proot
简写:mysql -u root -proot
退出:exit 或 ctrl+c
MySQL常见命令
- 查看当前所有数据库:show databases;
- 查看表结构:desc 表名;
- 打开指定的库:use 库名;
- 查看当前库的所有表:show tables;
- 查看指定表的创建语句:show create tables 表名;
- 查看其他库的所有表:show table from 库名;
- 查看MySQL服务端版本
- 方式一:在MySQL客户端输入:select version();
- 方式二:在windows客户端输入:mysql --version 或 mysql -V
MySQL数据类型
类型选择原则:所选择的类型越简单越好,能保存数值的类型越小越好
数值型
整型
- 如果不设置无符号还是有符号,默认是有符号,设置无符号需要在设定的类型后方添加 unsigned关键字
- 如果插入的数值超出了整型的范围,就会报out of range异常,并且插入临界值
- 如果不设置长度,会有默认的长度,长度代表了显示的最大宽度,如果不够会用0在左边填充,但必须在类型后搭配 zerofill使用,并默认变为无符号整型
小数
M:整数部位+小数部位
D:小数部位
如果超过范围,则插入临界值
M和D都可以省略
如果是decimal,则M默认为10,D默认为0
如果是float和double,则会根据插入数值的精度来决定精度
定点型的精确度较高,要求精度较高时使用,如货币运算
字符型
较短的文本 (保存MySQL中较短的字符串)
较长的文本 (text、blob较大的二进制)
日期型
datetime不受时区影响
timestamp受时区、语法模式、版本的影响 (更能反映当前时区)
查看时区:show variables like ‘time_zone’;
设置时区:set time_zone=‘+9:00’;
MySQL的约束
primary key:主键
- 相当于唯一约束+非空约束组合,主键列不允许重复 不允许为空
- 每个表最多一个主键,允许字段组合 (不推荐)
auto_increment:自增长
- 实现主键自增长,加在主键列上,必须是整数类型
- 默认情况初始值为1,新增一条数据自动加1
语法:字段名 数据类型 primary key auto_increment
not null:非空
保证该字段的值不能为空 (姓名、学号)
unique:唯一
字段值唯一,可以为空,可以设置多个,允许字段组合 (不推荐)
default:默认
保证该字段有默认值 (性别)
zerofill:零填充
foreign key:外键
外键,用于限制两个表的关系,保证该字段的值必须来自于主表的关联列的值
- 在从表中设置外键关系,引用主表中某列的值
- 从表的外键列的类型和主表的关联列的类型要求一致或兼容,名称无要求
- 主表的关联列必须是一个key (一般是主键或唯一)
- 插入数据时,先插入主表,再插入从表;删除数据时,先删除从表,再删除主表
SQL的语言分类
DDL (Data Define Languge)
数据定义语言,用于库和表的创建、修改、删除
关键字:create, alter, drop等
链接:https://blog.csdn.net/fhsbvs/article/details/120283538
DML (Data Manipulate Language)
数据操纵语言,用于添加、删除、修改数据库记录
关键字:insert, delete, update 等
链接:https://blog.csdn.net/fhsbvs/article/details/120283538
DQL (Data Query Language)
数据查询语言,用来查询数据库中表的记录(数据)
关键字:select, where 等
链接:https://blog.csdn.net/fhsbvs/article/details/120216133
DCL (Data Control Language)
数据控制语言,用来创建数据库用户,控制数据库访问权限
管理用户
-- 查询用户
use mysql;
select * from user;
-- 创建用户
create user '用户名'@'主机名' identified by '密码';
-- 修改密码
alter user '用户名'@'主机名' identified with mysql_native_password by '新密码';
-- 删除用户
drop user '用户名'@'主机名';
注意:主机名可以使用%通配
权限控制
权限分类
- ALL 或 ALL PRIVILEGES:所有权限
- SELECT、INSERT、UPDATE、DELETE:查询、插入、修改、删除
- ALTER、DROP、CREATE:修改表、删除数据库/表/视图、创建数据库/表
-- 查询权限
show grants user '用户名'@'主机名';
-- 授予权限
grant 权限列表 on 数据库名.表名 to '用户名'@'主机名';
-- 撤销权限
revoke 权限列表 on 数据库名.表名 from '用户名'@'主机名';
注意
1.多个权限之间,使用逗号分隔
2.授权时,数据库名和表名可以使用*进行通配,代表所有
TCL (Transaction Control Language)
数据事务语言
链接:https://blog.csdn.net/fhsbvs/article/details/120402105
存储引擎
存储引擎是存储数据、建立索引、更新/查询数据等技术的实现方式
存储引擎是基于表的,而不是数据库,也被称为表类型
MySQL体系结构
连接层
最上层是一些客户端和链接服务,主要完成一些类似于连接处理、授权认证、及相关的安全方案。服务器也会为安全接入的每个客户端验证它所具有的操作权限。
服务层
第二层架构主要完成大多数的核心服务功能,如SQL接口,并完成缓存的查询,SQL的分析和优化,部分内置函数的执行。所有跨存储引擎的功能也在这一层实现,如 过程、函数等。
引擎层
存储引擎真正的负责了MySOL中数据的存储和提取,服务器通过API和存储引擎进行通信。不同的存储引擎具有不同的功能,这样我们可以根据自己的需要,来选取合适的存储引擎。
存储层
主要是将数据存储在文件系统之上,并完成与存储引擎的交互。
指定存储引擎:
查看mysql支持的存储引擎:show engines;
InnoDB
索引
概述:高效获取数据的有序数据结构
优缺点
- 提高查询效率,提高排序效率
- 占用空间,影响增删改的效率
索引结构
二叉树
顺序插入时,会形成一个链表,查询性能降低;大数据情况下层级较深,检索速度慢
红黑树
大数据情况下层级较深,检索速度慢
B-Tree
以一颗最大度数为5的b-tree为例 (每个节点最多存储4个key,5个指针)
B+Tree
以一颗最大度数为4的b+tree为例
区别于B-Tree:
- 所有的数据都会出现在叶子节点
- 叶子节点形成一个单向链表
MySQL索引
在原B+Tree的基础上,增加一个指向相邻叶子节点的链表指针,形成了带有顺序指针的B+Tree,提高区间访问的性能
Hash
哈希索引是采用一定的hash算法,将键值换成新的hash值,映射到对应的位置,存储在hash表中,如果两个或多个键值映射到相同位置,就产生了hash冲突,可以用链表解决。
特点:
- 只能用于对等比较 (=,in),不支持范围查询 (between,<,>,…)
- 无法利用索引完成排序操作
- 查询效率高,通常一次检索就可以了,效率通常高于B+Tree索引
在MySQL中,支持hash索引的是Memory引擎,而InnoDB中具有自适应hash功能,hash索引是存储引擎根据B+Tree索引在指定条件下自动构建的。
索引分类
索引语法
性能分析
查看执行频率:
show [session | global] status like ‘Com_______’;
慢查询日志
慢查询日志记录了所有执行时间超过指定参数 (默认10秒)的所有SQL语句的日志
查看慢查询日志状态:show variables like ‘slow_query_log’;
-- 默认没有开启,需要在MySQL的配置文件 (/etc/my.cnf)中配置:
-- 开启MySQL慢日志查询开关
slow_query_log=1
-- 设置慢日志的时间为2秒,SQL语句执行时间超过两秒,就会视为慢查询并记录
long_query_time=2
-- 配置完毕之后,需要重启MySQL服务
查看慢日志文件中记录的信息:/var/lib/mysql/localhost-slow.log
profile详情
-- 查看当前MySQL是否支持
select @@have_profiling;
-- 默认是关闭的,开启
set [session | global] profiling=1;
查看每一条SQL的耗时情况:show profiles;
查看指定query_id的SQL语句各个阶段的耗时情况:show profile for query query_id;
查看指定query_id的SQL语句CPU的使用情况:show profile cpu for query query_id;
explain / desc
获取MySQL如何执行select语句的信息,执行过程中表如何连接和连接顺序
在select语句之前加上关键字 explain/desc:explain select 字段列表 from 表名 where 条件;
索引使用
最左前缀法则
- 如果是联合索引,查询从索引的最左列开始,且不跳过索引中的列
- 如果跳跃某一列,索引将部分失效 (后面的字段索引失效)
范围查询
- 联合索引中,出现范围查询 (>,<),范围查询右侧的列索引失效
- 业务允许的范围内可以使用 (>=,<=),索引不会失效
索引失效
- 在索引列上进行运算操作,或者使用函数,索引将失效
- 字符串类型字段使用时不加引号,索引将失效
- 尾部模糊匹配索引不会失效,头部模糊匹配索引失效
- or连接条件,如果or前条件中有索引,后面列中没索引,索引全部失效
- MySQL评估使用索引比全表更慢,则不使用索引
- is null 或 is not null 可能会引起索引失效,根据表中数据决策
如果为空的数据大于不为空的,is null 会失效
如果为空的数据小于不为空的,is not null 会失效
SQL提示
在SQL语句中加入提示来达到优化操作的目的
语法:select 字段名 from 表名 [use|ignore|force] index(字段名) where …;
- use index; 使用某个索引
- ignore index; 忽略某个索引
- force index; 必须使用某个索引
覆盖索引
查询使用索引,并且使用需要返回的列,解决回表查询
在非聚集索引中查询到索引字段信息以及主键信息,但是查询列表中还需要其他字段信息,就只能回表到聚集索引中找到主键信息返回另外的字段信息。
前缀索引
当字段类型为字符串时,有时候需要索引很长的字符串,索引变的很大,降低查询效率,可以只将字符串的一部分前缀建立索引,可以节约索引空间,提高索引效率。
语法:create index 索引名 on 表名(字段名(数字));
根据索引的选择性来决定,指不重复的索引值 (基数)和数据表的记录总数的比值,索引选择性越高查询效率越高,唯一索引的选择性是1,这是最好的索引选择性:
select count(distinct 字段名) / count(*) from 表名;
select count(distinct substring(字段名,数字,数字)) / count(*) from 表名;
设计原则
SQL优化
插入数据
- 批量插入
- 手动提交事务
- 主键顺序插入
主键优化
页分裂
主键乱序的情况可能导致页分裂
页合并
删除记录时并没有被物理删除,只是记录被标记为删除,空间变得可以被其他记录使用
主键设计原则
- 满足业务需求的情况下,尽量降低主键的长度
- 插入数据时尽量选择顺序插入,选择AUTO_INCREMENT自增主键
- 尽量不使用UUID或其他自然主键,如身份证号
order by 优化
- 表现
- using index:直接通过索引返回数据,性能高
- using filesort:需要将返回的结果在排序缓冲区排序
- 根据排序字段建立合适的索引,多字段排序时,也遵循最左前缀法则
- 尽量使用覆盖索引
- 多字段排序,一个升序一个降序,此时需要注意联合索引创建时的规则
group by 优化
- 通过索引来提高效率
- 索引的使用满足最左前缀法则
limit 优化
- 通过创建覆盖索引 + 子查询的形式进行优化
- 先分页查出主键,再通过主键查询记录集合
count 优化
排序效率:count(字段) < count(主键) < count(1) < count(*)
update 优化
- 尽量根据主键/索引字段进行数据更新
- InnoDB的行锁是针对索引加的锁,不是针对记录加的锁,并且该索引不能失效,否则会从行锁升级为表锁
视图、存储过程
链接:https://blog.csdn.net/fhsbvs/article/details/120402105
触发器
- 添加/更新/删除操作之前或之后,触发并执行定义的SQL语句集合
- 可以协助应用在数据库确保数据的完整性,日志记录,数据校验等
- 使用别名OLD 和 NEW来引用触发器中发生变化的记录内容,现在只支持行级触发,不支持语句级触发
创建
查看:show triggers;
删除
- drop trigger [schema name.]trigger_name;
- 如果没有指定 schema name,默认为当前数据库
应用
锁
锁是计算机协调多个进程或线程并发访问某一资源的机制
全局锁
表级锁
每次操作锁住整张表,锁定粒度大,锁冲突概率高,并发度最低
元数据锁
- 加锁过程是系统自动控制,无需显示使用,访问表的时候自动加上
- MDL锁主要作用是维护表元数据 (表结构)的数据一致性
- 为了避免DML与DDL冲突,保证读写的正确性
意向锁
- 为了避免DML在执行时,加的行锁与表锁的冲突
- 表锁不用检查每行数据是否加锁,使用意向锁来减少表锁的检查
意向共享锁 (IS)
由语句select … lock in share mode添加
与表锁共享锁 (read)兼容,与表锁排他锁 (write)互斥
意向排他锁 (IX)
由insert、update、delete、select … for update添加
与表锁共享锁 (read)及排他锁 (write)都互斥,意向锁之间不互斥
行级锁
- 每次操作锁住对应的行数据,锁粒度最小,冲突概率低,并发度高
- 通过对索引上的索引项加锁实现,不是对记录加的锁
行锁 (Record Lock)
锁定单个行记录的锁,防止其他事务对此行进行update和delete。在RC、RR隔离级别下都支持
共享锁 (S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁
排他锁 (X):允许获取排他锁的事务更新数据,阻止其他事务获得相同数据集的共享锁和排他锁
间隙锁 (Gap Lock)
锁定索引记录间隙 (不含该记录),确保索引记录间隙不变,防止其他事务在这个间院进行inse,产生幻读。在RR隔离级别下都支持
间隙锁唯一目的是防止其他事务插入间隙,间隙锁可以共存,一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用间隙锁
临键锁 (Next-Key Lock)
行锁和间隙锁组合,同时锁住数据,并锁住数据前面的间隙Gap。在RR隔离级别下支持
InnoDB引擎
逻辑存储结构
架构
总结构图
内存结构
1
2
3
4
磁盘结构
1
2
3
后台线程
事务原理
redo log
- 重做日志,记录事务提交时数据页的物理修改,实现事务的持久性
- 重做日志缓冲 (redo log buffer),在内存中
- 重做日志文件 (redo log file),在磁盘中
- 事务提交之后会把所有修改信息都存到该日志文件中,用于在刷新脏页到磁盘发生错误时,进行数据恢复使用
undo log
回滚日志,记录数据被修改前的信息,作用包含:提供回滚和MVCC (多版本并发控制)
实现事务
- 原子性:undo log
- 持久性:redo log
- 一致性:redo log + undo log
- 隔离性:MVCC + 锁
MVCC
记录隐藏字段
undo log版本链
readview
ReadView (读视图) 是快照读SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务 (未提交的) id
日志
错误日志
二进制日志
查询日志
慢查询日志
从主复制
主从复制是指将主数据库的DDL和 DML 操作通过二进制日志传到从库服务器中,然后在从库上对这些日志重新执行(也叫重做),从而使得从库和主库的数据保持同步
MySQL支持一台主库同时向多台从库进行复制,从库同时也可以作为其他从服务器的主库,实现链状复制
主库 (Master)、从库 (Slave)
优点:
- 主库出现问题,可以快速切换到从库提供服务
- 实现读写分离,降低主库的访问压力
- 可以在从库中执行备份,以避免备份期间影响主库服务
原理
搭建
主库配置
从库配置
分库分表
分库分表中心思想是将数据分散存储,使得单一数据库/表的数据量变小来缓解单一数据库的性能问题,达到提升数据库性能的目的。
垂直拆分
水平拆分
MyCat
开源的、活跃的、基于Java语言编写的MySQL数据库中间件,像使用MySQL一样来使用MyCat
下载地址:http://www.mycat.org.cn/mycat1.html
读写分离
一主一从 读写分离
balance
问题:主节点Master宕机之后,业务系统就只能读,不能写入数据了
双主双从 读写分离
其他内容
MySQL查询表数据量
-- 将${ DATABASE _ NAME }替换为要查询的数据库的名称
-- 该查询将返回指定数据库中的表列表,以及它们各自的数据大小(以兆为单位)
SELECT table_name AS `Table`,
round((( data_length + index_length ) / 1024 / 1024 ), 2 ) AS `Size in MB`
FROM information_schema.TABLES
WHERE table_schema = "${DATABASE_NAME}"
ORDER BY ( data_length + index_length ) DESC;
MySQL大表加索引
# 1、创建一张和原表结构一样的空表,只是表名不一样
CREATE TABLE tb_name_tmp LIKE tb_name;
# 2、把新建的空表非主键索引都删掉,因为这样在往新表导数据的时候效率会很快
#(因为除了必要的主键以外,不用再去建立其它索引数据了)
ALTER TABLE tb_name_tmp DROP INDEX index_name;
# 3、从旧表往主表里导数据,如果数据太大,建议分批导入,只需确保无重复数据就行,因为导入数据太大,会很占用资源
# (内存,磁盘io, cpu等),可能会影响旧表在线上的业务。每批次100万条数据导入,基本上每次都是在 20s左右
SELECT MIN(id) AS min,MAX(id) AS max FROM tb_name;
INSERT INTO tb_name_tmp SELECT * FROM tb_name WHERE id BETWEEN start_id AND end_id;
# 4、数据导完后,再对新表进行添加索引
ALTER TABLE `tb_name_tmp` ADD INDEX index_name;
# 5、当大部分数据导入后,索引也建立好了,但是旧表数据量还是会因业务的增长而增长,这时候为了确保新旧表的数据一至性和平滑切换
# 建议写一个脚本,判断当旧表的数据行数与新表一致时,就切换。比如以 max(id)来判断
SELECT COUNT(*) FROM tb_name;
SELECT COUNT(*) FROM tb_name_tmp;
RENAME TABLE tb_name TO tb_name_tmp1;
RENAME TABLE tb_name_tmp TO tb_name;
MySQL清除表空间碎片
表的碎片空间是指表中已经被删除的记录所占用的空间,这些空间会随着表的增删改操作而不断产生。
当表中的记录被删除时,这些记录所占用的空间并不会立即被释放,而是被标记为可重用的空间,等待下一次插入记录时再被使用。这样就会导致表中出现碎片空间,影响表的性能和存储空间的利用率。为了解决这个问题,可以定期进行表的优化和整理,或使用专业的数据库管理工具来管理碎片空间。
注意
- 在清除数据库表碎片之前,需要备份数据库以防止数据丢失
- 需要确保没有正在运行的查询或事务,以免清除过程中出现错误
- 清除数据库表碎片可能需要一定的时间,需要在维护期间进行
# 1、查看某个表的碎片大小 (data_free)
SHOW TABLE STATUS LIKE '表名';
# 2、列出所有已经产生碎片的表
SELECT table_schema db, table_name, data_free, `engine`
FROM information_schema.tables
WHERE table_schema NOT IN ('information_schema', 'mysql')
AND data_free > 0 ORDER BY data_free DESC;
# 3、清除表碎片
方式一:optimize table 表名;
方式二:alter table 表名 engine=InnoDB;
方式一 vs 方式二
- 相同:两者都会对表的数据和索引数据进行重建,对空间碎片进行回收,提高I/O资源
- 两者执行的大致流程:
1)获取MDL写锁
2)降级为MDL读锁,重建表(时间消耗最长)
3)升级MDL写锁
4)释放MDL锁
- 两者执行的大致流程:
- 不同:optimize相当于recreate + analyze,alter相当于recreate
“recreate + analyze” 是指重新创建数据库表并分析表的统计信息,以便优化查询性能。这个过程会删除表中的数据并重新构建表,然后重新计算表的统计信息。
“recreate” 通常指删除现有的数据库表并重新创建一个新的表。这个过程会清除表中的所有数据,因此需要在执行之前备份数据。