MySQL
2023-02-25 13:47:36 0 举报
AI智能生成
Mysql
作者其他创作
大纲/内容
SQL 基础
卸载 / 安装 / 修改远程链接
https://dev.mysql.com/downloads/mysql/
卸载
停止当前服务mysql: systemctl stop mysqld
查看当前MySQL安装状况 rpm -qa|grep -i mysql
卸载上述命令查询出的所有已安装程序
mysql5
rpm -e --nodeps mysql57-community-release
rpm -e --nodeps mysql-community-server
rpm -e --nodeps mysql-community-common
rpm -e --nodeps mysql-community-libs
rpm -e --nodeps mysql-community-client
mysql8
rpm -e --nodeps mysql-community-common
rpm -e --nodeps mysql-community-server
rpm -e --nodeps mysql-community-libs
rpm -e --nodeps mysql-community-icu-data-files
rpm -e --nodeps mysql-community-client
rpm -e --nodeps mysql-community-client-plugins
查找并删除残留文件
find / -name mysql
mysql5
rm -rf /var/lib/mysql
rm -rf /usr/share/mysql
rm -rf /etc/selinux/targeted/active/modules/100/mysql
rm -rf /etc/selinux/targeted/tmp/modules/100/mysql
................
docker 镜像文件配置不需要删除
mysql8
rm -rf /etc/selinux/targeted/active/modules/100/mysql
rm -rf /etc/selinux/targeted/tmp/modules/100/mysql
rm -rf /usr/lib64/mysql
rm -rf /var/lib/mysql
................
docker 镜像文件配置不需要删除
删除配置文件和日志
rm -f /etc/my.cnf*
rm -f /var/log/mysqld.log
安装
查询是否有依赖没有需要域名yum install
rpm -qa|grep libaio
rpm -qa|grep net-tools
检查/tmp临时目录权限,如果不是777则需要设置限权
ll -a /
chmod -R 777 /tmp
上传文件并解压
cd /opt
tar xvf mysql-8.0.29-1.el7.x86_64.rpm-bundle.tar
安装
rpm -ivh mysql-community-common-8.0.29-1.el7.x86_64.rpm
rpm -ivh mysql-community-client-plugins-8.0.29-1.el7.x86_64.rpm
rpm -ivh mysql-community-libs-8.0.29-1.el7.x86_64.rpm
rpm -ivh mysql-community-icu-data-files-8.0.29-1.el7.x86_64.rpm
rpm -ivh mysql-community-client-8.0.29-1.el7.x86_64.rpm
rpm -ivh mysql-community-server-8.0.29-1.el7.x86_64.rpm
# -i, --install 安装软件包
# -v, --verbose 提供更多的详细信息输出
# -h, --hash 软件包安装的时候列出哈希标记 (和 -v 一起使用效果更好),展示进度条
查验是否安装成功并查验版本
rpm -qa|grep -i mysql
mysqladmin --version
初始化mysql
#初始化数据目录并生成初始密码
mysqld --initialize --user=mysql
#查看数据目录
ls /var/lib/mysql/
查找初始密码
#mysql安装完成之后,在/var/log/mysqld.log文件中给root生成了一个默认密码。通过下面的方式找到root默认密码,然后登录mysql。
grep 'temporary password' /var/log/mysqld.log
或者使用 more /var/log/mysqld.log
修改初始密码
ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
-- 或者
SET password FOR 'root'@'localhost'= '123456';
远程链接
- `Host=localhost`,表示只能通过本机客户端去访问。
- `Host=%` ,表示所有IP都有连接权限。
UPDATE user SET Host = '%' WHERE User ='root';
FLUSH PRIVILEGES;
配置新连接报错:错误号码 2058,出现这个原因是MySQL 8 之前的版本中加密规则是mysql_native_password,而在MySQL 8之后,加密规则是caching_sha2_password。
解决方案有两种,一种是升级SQLyog和Navicat(因此,新版SQLyog不会出现此问题),另一种是把MySQL用户登录密码加密规则还原成mysql_native_password。
**解决方法:**Linux下 mysql -uroot -p 登录你的 MySQL 数据库,然后 执行这条SQL:
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
mysql5 ---> 8 区别 UTF-8
utf8mb3 :阉割过的 utf8 字符集,只使用1~3个字节表示字符。(无法存储emoji表情
utf8mb4 :正宗的 utf8 字符集,使用1~4个字节表示字符。
MySQL 8版本之前,默认字符集为 latin1 ,不支持中文,使用前必须设置字符集为utf8(utf8mb3)或utf8mb4。从MySQL 8开始,数据库的默认字符集为 utf8mb4 ,从而避免中文乱码的问题。
登录MySQL服务器 与 用户管理 及 权限管理
完整语句
mysql –h hostname|hostIP –P port –u username –p DatabaseName –e 'SQL语句'
创建用户
语法:CREATE USER 用户名 [IDENTIFIED BY '密码'][,用户名 [IDENTIFIED BY '密码']];
-- 默认host是 %
CREATE USER zhang3 IDENTIFIED BY '123456';
-- 进允许本地连接
CREATE USER 'li4'@'localhost' IDENTIFIED BY '123456';
删除用户
语法 : DROP USER user[,user]…;
DROP USER zhang3; -- 默认删除host为%的用户
DROP USER 'wang5'@'localhost';
权限管理
查看有哪些权限:SHOW PRIVILEGES;
权限
(1) `CREATE和DROP权限` 可以创建新的数据库和表,或删除已有的数据库和表。
(2) `SELECT、INSERT、UPDATE和DELETE权限` 允许在一个数据库现有的表上实施操作。
(3) `INDEX权限` 允许创建或删除索引。
(4) `ALTER权限` 可以使用ALTER TABLE来更改表的结构和重新命名表。
(5) `GRANT权限` 允许授权给其他用户,可用于数据库、表和保存的程序。
设置权限
语法: GRANT 权限1,权限2,…权限n ON 数据库名称.表名称 TO 用户名@用户地址 [IDENTIFIED BY ‘密码口令’];
GRANT ALL PRIVILEGES ON *.* TO 'tian7'@'%'; --授权所有限权,除给其他用户授权外
放到授权最后,给其他用户授予 授权 的权限
WITH GRANT OPTION
GRANT SELECT, INSERT, UPDATE ON atguigudb.* TO 'zhao6'@'%'; --授权
查看当前用户或其他用户限权
当前用户:SHOW GRANTS;
其他用户:SHOW GRANTS FOR '用户名'@'主机地址';
回收限权
REVOKE 权限1, 权限2, …权限n ON 数据库名称.表名称 FROM '用户名'@'主机地址';
收回某库限权:REVOKE SELECT ON atguigudb.* FROM 'zhao6'@'%';
收回所有限权:REVOKE ALL PRIVILEGES ON *.* FROM 'zhao6'@'%';
SQL语句
sql_mode
宽松模式 vs 严格模式
宽松模式:<br>执行错误的SQL或插入不规范的数据,也会被接受,并且不报错。<br><br>严格模式:<br>执行错误的SQL或插入不规范的数据,会报错。MySQL5.7版本开始就将sql_mode默认值设置为了严格模式。
查看和设置sql_mode
查询当前sql_mode模式:
SELECT @@session.sql_mode;
SELECT @@global.sql_mode;
-- 或者
SHOW VARIABLES LIKE 'sql_mode'; --session级别
设置sql_mode模式:
SET GLOBAL sql_mode = '模式值'; --全局,要重新启动客户端生效,重启MySQL服务后失效
SET SESSION sql_mode = '模式值'; --当前会话生效效,关闭当前会话就不生效了。可以省略SESSION关键字
在 /etc/my.cnf 中配置,永久生效
[mysqld]
sql-mode = '模式值'
常用模式
设置sql_mode 模式 :
SET SESSION sql_mode =
'ONLY_FULL_GROUP_BY,
STRICT_TRANS_TABLES,
NO_ZERO_IN_DATE,
NO_ZERO_DATE,
ERROR_FOR_DIVISION_BY_ZERO,
NO_ENGINE_SUBSTITUTION';
sql_mode说明
ONLY_FULL_GROUP_BY
对于GROUP BY聚合操作,SELECT子句中只能包含函数和 GROUP BY 中出现的字段。
STRICT_TRANS_TABLES
- 对于支持事务的表,如果发现某个值缺失或非法,MySQL将抛出错误,语句会停止运行并回滚。
- 对于不支持事务的表,不做限制,提高性能。
NO_ZERO_IN_DATE
不允许日期和月份为零。
NO_ZERO_DATE
MySQL数据库不允许插入零日期,插入零日期会抛出错误而不是警告。
ERROR_FOR_DIVISION_BY_ZERO
在INSERT或UPDATE过程中,如果数据被零除,则产生错误而非警告。如果未给出该模式,那么数据被零除时MySQL返回NULL。
NO_ENGINE_SUBSTITUTION
如果需要的存储引擎被禁用或不存在,那么抛出错误。不设置此值时,用默认的存储引擎替代。
SQL 高级-逻辑架构
逻辑架构剖析图
SQL语句执行流程图(一)
SQL语句执行流程图(二)
SQL流程话术
MySQL服务器之外的客户端程序,与具体的语言相关,例如Java中的JDBC,图形用户界面SQLyog等。`本质上都是在TCP连接上通过MySQL协议和MySQL服务器进行通信。`
SQL语句通过拿取链接和数据库建立TCP链接
1.经过三次握手建立连接成功后, MySQL 服务器对 TCP 传输过来的账号密码做`身份认证、权限获取`。
2. TCP 连接收到请求后,必须要分配给一个线程专门与这个客户端的交互。所以还会有个线程池,去走后面的流程。每一个连接从线程池中获取线程,省去了创建和销毁线程的开销。
SQL语句通过缓存和缓冲器;查询缓存是否有该语句为Key值的查询结果,如果有,直接返回,没有继续查询
mysql8舍弃这一部分,太鸡肋;要求完全一直,包括 空格 等一系列信息,太苛刻
通过SQL Interface 判断是DDL DML,并拿到相应接口
通过SQL解析器 Parser,解析SQL语句并生成一棵解析树 ; 并且判断语句是否有错误,包括语法错误和逻辑错误
通过 Optimizer 语句优化器对SQL语句优化
通过调用 Storage Engines 的各种引擎来查询结果
Sql执行流程开启查看
SHOW VARIABLES LIKE '%profiling%';
SET profiling = 1; -- profiling = ON
profiling=0 代表关闭,我们需要把 profiling 打开,即设置为 1:
显示最近几次查询:SHOW PROFILES;
步骤
- 主要步骤: <br> - checking permissions:检查权限 <br> - Opening tables:打开表<br> - init : 初始化 <br> - System lock :系统锁<br> - optimizing : 优化sql<br> - statistics : 统计<br> - preparing :准备执行<br> - executing :执行sql<br> - Sending data :发送数据<br> - Sorting result :排序<br> - end :结束<br> - query end :查询 结束<br> - closing tables : 关闭表 /去除TMP 表<br> - freeing items : 释放<br> - cleaning up :清理
执行引擎:
查看MySQL提供什么存储引擎: SHOW ENGINES;
也可以通过以下语句查看默认的存储引擎:SHOW VARIABLES LIKE '%default_storage_engine%';
设置默认引擎:SET DEFAULT_STORAGE_ENGINE=MyISAM;
各类引擎说明
分支主题
分支主题
MyISAM 和 InnoDB 引擎的区别
InnoDB 和 MyISAM 对比 图(一)
SQL高级-索引与树
索引
概念
索引(index) 帮助MySQL 高效获取数据 的 数据结构 ;
优点:
(1).快速找到内容,降低数据库IO成本(次数)<br>(2).通过创建唯一索引,保证数据的唯一性<br>(3).加速表和表之间的连接 。对于有依赖关系的子表和父表联合查询时,可以提高查询速度。<br> (4).在使用分组和排序子句进行数据查询时,减少查询时间,降低CPU的消耗。<br>
缺点:
索引维护成本高 、 占用储存空间 、在增删改情况多的时候,调整索引成本高
分类
### 索引分类<br><br>- 从功能逻辑上划分:普通索引、唯一索引、主键索引、全文索引。<br>- 按照作用字段个数划分:单列索引和联合索引。<br>- 按照物理实现方式划分:聚簇索引和非聚簇索引。<br>
普通索引指在数据表中非唯一和主键值的列
唯一索引是给唯一键建立索引
主键索引InnoDB执行引擎自动创建,手动创建表格时创建索引也可以
全文索引不建议创建,会导致表与表关系错综复杂且难以管理
单例索引是指一个字段建立索引;
联合索引指多字段建立索引;使用多字段查找时会速度更快
聚簇索引 是 指 主键索
聚簇索引储存 : 索引值(主键值) 数据页 (指向对应数据行的物理指针 / 磁盘块)
InnoDB引擎的表中必须要有一个聚簇索引 ; 没有聚簇索引也会自动选择一个唯一键称为聚簇索引,如果没有唯一键那么就会创立一个隐藏的聚簇索引
<font color="#000000">(1)</font><b style="">索引和数据保存在同一个B+树中</b><br><font color="#000000">(2)</font><b><font color="#000000">页内的记录</font></b><font color="#000000">是按照</font><font color="#e855a4">主键的大小</font><font color="#000000">顺序排成一个</font><b style="">单向链表</b><font color="#000000"> 。</font><br><font color="#000000">(3)</font><b style=""><font color="#000000">页和页之间</font></b><font color="#000000">也是根据页中记录的</font><font color="#e855a4">主键的大小</font><font color="#000000">顺序排成一个</font><b style="">双向链表</b><font color="#000000"> 。</font><br><font color="#000000">(4)<b>非叶子节点</b>存储的是记录的</font><b>主键+页号</b><font color="#000000">。</font><br><font color="#000000">(5)<b>叶子节点</b>存储的是</font><b style="">完整的用户记录</b><font color="#000000">。</font><br>
优势:<br>(1)<b>数据访问更快 </b>,索引和数据保存在同一个B+树中,因此从聚簇索引中获取数据比非聚簇索引更快。<br>(2)聚簇索引对于主键的<b>排序查找和范围查找</b>速度非常快。 <br>(3)按照聚簇索引排列顺序,<b>查询</b>显示一定<b>范围数据</b>的时候,由于<b>数据都是紧密相连</b>,数据库可以从更少的数据块中提取数据,<b>节省</b>了大量的<b>IO</b>操作`。<br>
劣势:<br>(1)插入速度<b>严重依赖于插入顺序</b> ,<b>按照主键的顺序插入</b>是最快的方式,<font color="#e855a4"><b>否则将会出现页分裂</b>,<b>严重影响性能</b></font>。因此,对于InnoDB表,我们一般都会<b><font color="#e74f4c">定义一个自增的ID列为主键。 </font></b><br>(2)<b>更新主键的代价很高 </b>,因为将会导致被更新的行移动。因此,对于InnoDB表,我们一般<b><font color="#e74f4c">定义主键为不可更新</font></b>。<br>
非聚簇索引 是 指 非主键的普通索引
InnoDB:使用非聚簇索引查询时,需要根据非聚簇索引进行查询到相应的主键所在指针(物理地址)后,回表 根据主键地址查询数据库;保证主键
MyISAM:使用非聚簇索引查询时,通过非聚簇索引进行查询相应主键物理地址(指针)后,去数据文件中查找数据(根据主键地址查找到值后根据主键查找而非根据聚簇索引查找);
<b>介绍</b>:<br>(1)<b>页内的记录</b>是按照大小顺序排成一个<font color="#e74f4c"><b style="">单向链表</b>。</font><br>(2)<b>页和页之间</b>也是根据页中记录的大小顺序排成一个<font color="#e74f4c"><b>双向链表</b> 。</font><br>(3)<b>非叶子节点</b>存储的是<b><font color="#e855a4">记录</font></b>的<b><font color="#e74f4c">查询条件的值+页号</font></b><br>(4)<b>叶子节点存储</b>的并<b><font color="#e855a4">不是完整的用户记录</font></b>,而只是<b><font color="#e74f4c">查询条件+主键这两个列的值。</font></b><br>
InnoDB非聚簇索引回表图(一)
索引操作
<b><font color="#e74f4c">创建索引方式:</font></b>
<b><font color="#e74f4c">ALTER TABLE ADD ( 索引值1,索引值2,........ )</font></b><br>ALTER TABLE customer1 ADD PRIMARY KEY (id);-- 主键索引<br>ALTER TABLE customer1 ADD UNIQUE INDEX uk_no (customer_no);-- 唯一索引<br>ALTER TABLE customer1 ADD INDEX idx_name (customer_name);-- 普通索引<br>ALTER TABLE customer1 ADD INDEX idx_no_name (customer_no,customer_name); -- 复合索引<br>
<b><font color="#e74f4c">CREATE </font>索引名<font color="#e74f4c"> ON </font><font color="#000000">表名</font><font color="#e74f4c"> ( 索引值1,索引值2,....... )</font></b><br>CREATE PRIMARY KEY (id); --主键索引<br>CREATE UNIQUE INDEX uk_no ON customer1(customer_no); -- 唯一索引<br>CREATE INDEX idx_name ON customer1(customer_name);-- 普通索引<br>CREATE INDEX idx_no_name ON customer1(customer_no,customer_name); -- 复合索引<br>
<font color="#4ccbcd">对于Varchar类型的数据,如果数据过长,可以通过创建部分长度索引;<br>需要注意的是,前缀索引和函数索引都会导致一些查询时索引失效,因此需要根据实际情况进行权衡和选择。</font><br><b><font color="#e74f4c">CREATE INDEX </font><font color="#000000">索引名</font><font color="#e74f4c"> ON </font><font color="#000000">表名</font><font color="#e74f4c">(</font><font color="#000000">字段名(截取长度</font><font color="#e74f4c">));</font></b><br><font color="#5c4038">CREATE INDEX idx_address_prefix ON table_name(address(12));--前缀索引<br></font><b><font color="#e74f4c">CREATE INDEX </font><font color="#000000">索引名</font><font color="#e74f4c"> ON </font><font color="#000000">表名</font><font color="#e74f4c">(字段名(截取长度));</font></b><font color="#5c4038"><br>CREATE INDEX idx_address_func ON table_name(LEFT(address, 12));--函数索引</font><br>
查看索引方式
SHOW INDEX FROM customer;
删除索引
<b><font color="#e74f4c">DROP INDEX ON ; -- 删除单值、唯一、复合索引<br></font></b><font color="#5c4038">DROP INDEX idx_name ON customer;</font><br><b><font color="#e74f4c">ALTER TABLE <表名> MODIFY<列名> INT,DROP PRIMARY KEY; -- 删除主键索引(有主键自增)</font></b><br><font color="#5c4038">ALTER TABLE customer MODIFY id INT, DROP PRIMARY KEY; -- 删除主键索引(有主键自增)</font><br><b><font color="#e74f4c">ALTER TABLE <表名>DROP PRIMARY KEY; -- 删除主键索引(没有主键自增)</font></b><br><font color="#5c4038">ALTER TABLE customer DROP PRIMARY KEY; -- 删除主键索引(没有主键自增)</font><br>
索引的创建与否的判断依据
<b><font color="#e74f4c">**哪些情况适合创建索引:**</font></b><br><br>(1)<font color="#5c4038">主键自动建立唯一索引<br></font>(2)<font color="#5c4038">字段的值有唯一性的限制<br></font>(3)<font color="#5c4038">频繁作为WHERE查询条件的字段<br></font>(4)<font color="#5c4038">UPDATE、DELETE的WHERE条件列<br></font>(5)<font color="#5c4038"> 经常GROUP BY 和 ORDER BY的列<br></font>(6)<font color="#5c4038">DISTINCT字段需要创建索引- 多表JOIN时,对连接字段创建索引<br></font>(7)<font color="#5c4038"> 使用字符串前缀创建索引<br></font>(8)<font color="#5c4038"> 区分度高的列(重复的数据少)适合作为索引- 使用频繁的列,放到联合索引的左侧- 多个字段都需要创建索引时,联合索引优于单值索引</font><br>
<b><font color="#e74f4c">**哪些情况不要创建索引:**<br></font></b><br>(1)WHERE里用不到的字段不创建索引<br>(2) 表的数据记录太少<br>(3) 有大量重复数据的列上<br>(4)避免对经常增删改的表创建索引<br>(5)要定义冗余或重复的索引<br>(6) 删除不再使用或很少使用的索引<br>
树
概念:树有很多种,每个节点最多只能有两个子节点的一种形式称为二叉树。二叉树的子节点分为左节点和右节点。
二叉树
二叉搜索树BST
<b><font color="#e74f4c">二叉树基础上演示出左节点比父节点小,右节点比父节点大;特别说明:如果有相同的值,可以将该节点放在左子节点或右子节点。</font></b>
BST的生成演示:https://www.cs.usfca.edu/~galles/visualization/BST.html
<b><font color="#5c4038">问题:当节点都是小于父节点时,那么就会都在左边,形成类似于链表形式的树,不利于查找</font></b>
平衡二叉树AVL
<b><font color="#e74f4c">在搜索树基础上,添加了随时调整节点功能,使得树两边高度差值的绝对值小于等于1左右两边子树子树也是一颗平衡二叉树</font></b>
AVL的生成演示:https://www.cs.usfca.edu/~galles/visualization/AVLtree.html
<b><font color="#5c4038">问题:当海量数据存储,查询时无法将数据一下子加载到内存中,只能逐点加载(一个节点一次IO);磁盘IO次数和树的高度有关;海量数据导致树过高IO过于频繁,效率低下</font></b>
多叉树
在平衡二叉树基础上,非叶子节点上可以放多个数据;重新组织节点,减少节点数量,增加分叉,减少树的高度
问题:多叉树降低了高度,但是没有规定树中数据排放方式;
多叉树(一)
B树 B-Tree
经过发展,多叉树已经把书高度降得很低了,没有规定数据按照什么规则进行排放;所以出现了B树;
<b>B 树的搜索过程中,我们比较的次数并不少</b>,但如果把数据读取出来然后在<b>内存中进行比较</b>,这个<b>时间可以忽略不计</b>。而<b>读取磁盘块</b>本身<b>需要进行 I/O </b>操作,<b>消耗的时间比在内存中进行比较所需要的时间要多</b>,是数据查找用时的重要因素。B 树相比于平衡二叉树来说磁盘 I/O 操作要少 ,在数据查询中比平衡二叉树效率要高。所以只要<b><font color="#e74f4c">树的高度足够低,IO次数足够少,就可以提高查询性能 。</font></b><br>
B树数据是由一个个的磁盘块组成,一个磁盘块默认128KB;磁盘块内部存储: 主键值、指针 、data:主键外的其他数据值;
<b><font color="#e74f4c">非叶子节点内部:主键值、指针、键值的data数据<br>叶子节点内部:主键值和data数据</font></b>
<font color="#e74f4c">问题:①在大量数据情况下(千万):树存储信息都是完整数据,导致树的高度较高;<br> ②同高度下磁盘块之间没有关联性:对于特殊需求(查询范围内的值)查询不方便,在同一高度也需要多次IO查询</font><br>
示意图
B树简单示意图(一)
B树完整示意图(一)
B+树 B+ Tree
<b>介绍:B+树节点由数据页来组成的 <font color="#e74f4c">数据页就是磁盘块的另一种说法 </font></b>;<b>默认也是128KB</b> ; <br><b><font color="#e74f4c">数据页:目录项、主键值、数据值、指针(下一条记录next_record 或 下一个数据页和上一个数据页的双向链表);</font><br><font color="#5c4038">数据分布:从小到大或从大到小,由数据页的record_type决定</font></b><br>
<b><font color="#e74f4c">- record_type:表示记录的类型, 0是普通记录、 2是最小记录、 3 是最大记录、1是B+树非叶子节点记录(目录项记录)。<br>- next_record:表示下一条记录的相对位置,我们用箭头来表明下一条记录。</font></b><br><b><font color="#5c4038">- 各个列的值:这里只记录在 index_demo 表中的三个列,分别是 c1 、 c2 和 c3 。(示意图中显示)<br>- 其他信息:除了上述3种信息以外的所有信息,包括其他隐藏列的值以及记录的额外信息。</font></b><br>
在B+树的叶子节点层,双向链表形成了整个索引的顺序,这就可以实现范围查询和排序操作。同时,在非叶子节点上也可以设置同层次的节点之间的指针(非叶子节点之间由双向链表连接),这样可以提高非叶子节点的遍历效率。
B+树数据结构:非叶子节点 不存储数据,只存储对应的数据页和主键和主键值 叶子节点 存储数据值 和 双向链表;
特点:
<b>(1)B+树中非叶子节点的关键字也会同时存在在子节点中,并且是在子节点中所有关键字的最大值(或最小)。<br>(2)B+树中非叶子节点仅用于索引,不保存数据记录,跟记录有关的信息都放在叶子节点中。<br>(3)B+树中所有关键字都在叶子节点出现,叶子节点构成一个有序链表,而且叶子节点本身按照关键字的大小从小到大顺序链接。<br>(4)补充:IO的次数和树的高度有关,减少IO次数就需要降低树的高度;</b><br>
<b>B+树容纳数据量:</b><br>如果B+树只有1层,也就是只有1个用于存放用户记录的节点,最多能存放 16 条记录。<br> 如果B+树有2层,最多能存放 `1600×16=25600` 条记录。<br>如果B+树有3层,最多能存放 `1600×1600×16=40960000` 条记录。- 如果存储千万级别的数据,只需要三层就够了<br>
示意图
B+树单数据页横
示意图(一)
B+树单数据页竖
示意图(二)
B+树数据页
示意图(三)
B+树 完整模块示意图(一)
完整示意图(二)
B和B+树区别
相同条件下,数据量在千万之上,B+树的非叶子节点能存放更多的主键信息和数据页信息;而B树存放了指针和主键和完整数据情况下,数据会占用存储空间,导致B树的高度会更高;而高度越高,发生IO操作次数会更多;导致数据优势降低;所以在大量数据情况下,B+树优势更大,B树在小数据量情况下优势大;
B树存储的是指针和数据值和主键值,B+树非叶子节点存储的是数据页值和主键值;所以B+树的非叶子节点上能存储的数据会更多,树的高度会更低;在数据量非常庞大(千万级别)时,B+树比B树会更好,但是如果数据量不大那么B树会更有优势
补充:阿里规范:单表在2GB数据量以上或500w条数据以上才会推荐分库分表
SQL高级-索引优化
优化索引概念:MySQL中`提高性能`的一个最有效的方式是对数据表`设计合理的索引`。索引提供了高效访问数据的方法,并且加快查询的速度,因此索引对查询的速度有着至关重要的影响。<br>我们创建索引后,用不用索引,最终是优化器说了算。`优化器会基于开销选择索引`,怎么开销小就怎么来。不是基于规则,也不是基于语义。<br>另外`SQL语句是否使用索引,和数据库的版本、数据量、数据选择度(查询中选择的列数)都有关系`。
性能分析器:EXPLAIN<br>
介绍:EXPLAIN关键字可以<b>模拟优化器执行SQL查询语句</b>,从而知道MySQL是如何处理你的SQL语句的。<b>分析你的查询语句或是表结构的性能瓶颈</b>。<br><br>
演示
<b>多表关联:t1为驱动表,t2为被驱动表。<br>(在INNER(<font color="#e74f4c">内连接</font>)中,表数据少的为驱动表,LEFT(<font color="#e74f4c">左连接</font>) t1是驱动表 和RIGHT(<font color="#e74f4c">右连接</font>)中 t2是驱动表)<br><font color="#fc51fc" style="">EXPLAIN SELECT </font><font color="#5c4038" style="">*</font><font color="#fc51fc" style=""> FROM </font><font color="#5c4038" style="">t1</font><font color="#fc51fc" style=""> INNER JOIN </font><font color="#5c4038" style="">t2</font><font color="#000000" style="">;</font></b><br>
<b>单表查询:</b><b style=""><font color="#fc51fc"> EXPLAIN SELECT </font><font color="#5c4038">*</font><font color="#fc51fc"> FROM</font><font color="#5c4038"> t1</font><font color="#000000">;</font></b><br>
解析查询概念:
id:查询次数(IO次数) ;一般情况下都是1,子查询时会发生变化;值相同时是从上到下顺序执行,值不同时是从上到下顺序执行且执行IO次数是值
select_type:查询语句评级<br>
**SIMPLE:**简单查询。查询中不包含子查询或者UNION。
EXPLAIN SELECT <font color="#5c4038">*</font> FROM <font color="#5c4038">t1</font><font color="#000000">;</font>
**PRIMARY:**<b>主查询。查询中若包含子查询,则最外层查询被标记为PRIMARY。</b><br>**SUBQUERY:**<b>子查询。在SELECT或WHERE列表中包含了子查询。</b><br>
EXPLAIN SELECT <font color="#5c4038">*</font> FROM <font color="#5c4038">t3</font> WHERE <font color="#5c4038">id</font> = <font color="#bfbfbf">(</font> SELECT <font color="#5c4038">id</font> FROM <font color="#5c4038">t2</font> WHERE <font color="#5c4038">content= </font><font color="#e74f4c">'a'</font><font color="#bfbfbf">)</font><font color="#000000">;</font><br>
**DEPENDENT SUBQUREY:**<b>如果包含了子查询,并且查询语句不能被优化器转换为连接查询,并且子查询是`相关子查询(子查询基于外部数据列)`,则子查询就是DEPENDENT SUBQUREY。</b>
EXPLAIN SELECT <font color="#5c4038">* </font>FROM <font color="#5c4038">t3</font> <br>WHERE <font color="#5c4038">id</font> <font color="#000000">=</font> <font color="#bfbfbf">(</font> SELECT <font color="#5c4038">id</font> FROM <font color="#5c4038">t2</font> WHERE <font color="#5c4038">content </font><font color="#000000">=</font> <font color="#e74f4c">t3.content </font><font color="#bfbfbf">)</font><font color="#000000">;</font><br>
**UNCACHEABLE SUBQUREY:**<b>表示这个subquery的查询要受到外部系统变量的影响</b><br>
EXPLAIN SELECT <font color="#5c4038">*</font> FROM <font color="#5c4038">t3 </font><br>WHERE <font color="#5c4038">id</font> <font color="#000000">=</font> <font color="#bfbfbf">(</font> SELECT <font color="#5c4038">id</font> FROM <font color="#5c4038">t2</font> WHERE <font color="#5c4038">content</font> <font color="#000000">=</font> <font color="#e74f4c">@@character_set_server </font><font color="#bfbfbf">)</font><font color="#000000">;</font><br>
**UNION:**<b>对于包含UNION或者UNION ALL的查询语句,除了最左边的查询是PRIMARY,其余的查询都是UNION。<br>**UNION RESULT:**UNION会对查询结果进行查询去重,MYSQL会使用临时表来完成UNION查询的去重工作,针对这个临时表的查询就是"UNION RESULT"</b>。<br>
**DEPENDENT UNION:**<b>子查询中的UNION或者UNION ALL,除了最左边的查询是DEPENDENT SUBQUREY,其余的查询都是DEPENDENT UNION。</b>
**DERIVED:**<b>在包含`派生表(子查询在from子句中)`的查询中,MySQL会递归执行这些子查询,把结果放在临时表里。</b><br>
**MATERIALIZED:**<b>优化器对于包含子查询的语句,`如果选择将子查询物化后再与外层查询连接查询`,该子查询的类型就是MATERIALIZED。如下的例子中,查询优化器先将子查询转换成物化表,然后将t1和物化表进行连接查询。</b>
table : 使用的表<br>
partitions:分区命中情况,非分区表,为NULL<br>
type:<br>
<span style="font-weight: normal;">结果值从最好到最坏依次是: <br>system > </span>const <span style="font-weight: normal;">> eq_ref > </span>ref <span style="font-weight: normal;">> fulltext > ref_or_null > index_merge > unique_subquery > index_subquery ></span> range<span style="font-weight: normal;"> > index > </span>ALL
阿里巴巴开发手册要求:SQL 性能优化的目标:至少要达到 `range` 级别,要求是 `ref` 级别,最好是 `consts`级别。<br>
possiblie_keys:可能用到的索引<br>
key:实际用到的索引<br>
key_len:使用的字节数;(值越大越好)
计算公式:<br>
ref:显示与key中的索引进行比较的列或常量<br>
rows:查询所扫描的行数。越小越好<br>
filtered:最后查询出来的数据占所有服务器端检查行数(rows)的`百分比`。值越大越好。<br>
Extra:包含不适合在其他列中显示但十分重要的额外信息。通过这些额外信息来`理解MySQL到底将如何执行当前的查询语句`。<br>
**Impossible WHERE**:where子句的值总是false<br>
**Using where:**使用了where,但在where上有字段没有创建索引<br>
**Using temporary:**使了用临时表保存中间结果<br>
**Using filesort:**排序操作无法使用到索引,只能在内存中(记录较少时)或者磁盘中(记录较多时)进行排序(filesort)
**Using index:**使用了覆盖索引,表示直接访问索引就足够获取到所需要的数据,不需要通过索引回表<br>
**Using index condition:**叫作 `Index Condition Pushdown Optimization (索引下推优化ICP):找到满足条件的数据后进行判断是否满足Index中剩余条件是否符合,符合返回给server层,不满足就再找下一条<br>
**Using join buffer:**在连接查询时,当`被驱动表`不能有效的利用索引时,MySQL会提前申请一块内存空间(join buffer)来加快查询速度<br>
<b>`课外阅读:`在没有索引的情况下,为了优化多表连接,减少磁盘IO读取次数和数据遍历次数,MySQL为我们提供了很多不同的连接缓存的优化算法; <br>可参考https://blog.csdn.net/qq_35423190/article/details/120504960<br>- `Using join buffer (hash join)`**8.0新增:**连接缓存(hash连接) `速度更快`<br>- `Using join buffer (Block Nested Loop)`**5.7**:连接缓存(块嵌套循环)</b><br>
-- 显示sql语句执行时间<br>SET profiling = 1;<br>SHOW VARIABLES LIKE '%profiling%';<br>SHOW PROFILES;
索引失效
单表索引失效:<br>
计算 、 函数 导致索引失效
模糊查询 LIKE 中%在前面(全表扫描),索引失效
不等于 ( != 或者 <> )导致索引失效
IS NOT NULL 导致索引失效
数据库中的数据的<b>索引列的NULL值达到比较高的比例</b>的时候`,即使在<b>IS NOT NULL 的情况下 MySQL的查询优化器会选择使用索引</b>,<b>此时type的值是range(范围查询)</b><br>
类型转换导致索引失效
EXPLAIN SELECT * FROM emp WHERE <b>name= <font color="#ff0000">'</font>123<font color="#ff0000">' </font></b>; <br>EXPLAIN SELECT * FROM emp WHERE <b>name= 123 </b>; --索引失效<br>name 是 varchar 类型数据 输入查询条件 是 int 类型,类型转换
全值匹配我最爱(查询语句效率最高)<br>
左前缀法则:联合索引需要遵循,查询从最左边的索引开始,不能跨越索引;<br>如:索引index_test(A,B,C)中,三个列组成一个联合索引,查询条件如果只有A和C,那么B,C都不会被索引使用;<br> 使用B或者C或者B,C;不使用A,那么这个索引就不会被使用;
索引中范围条件右边的列失效,如果范围条件对于优化器来说不合适,那么就会直接全表扫描;索引失效<br>
关联查询优化:<br>
左外连接:左表是驱动表(会进行全表扫描),右表是被驱动表;被驱动表会根据有用的索引进行查找,如果被驱动表没有合适的索引,那么就被驱动表也会全表扫描<br>
被驱动表没有索引 : 驱动表全部数据 * 被驱动表所有数据 ( 16 * 20 次)<br>被驱动表有索引 : 驱动表数据 * 被驱动表数据( 16 * 1 次)
内连接:<br> ①如果都有(都没有)索引:SQL优化器会自动选择数据少的表作为驱动表进行全表扫描,另一个是被驱动表;<br> ②如果一个有表索引,一个表没有索引情况下,那么就会选择没有索引的作为驱动表;<br>
总结:<br>①保证被驱动表的JOIN字段已经创建了索引<br>②需要JOIN 的字段,数据类型保持绝对一致。<br>③LEFT JOIN 时,选择小表作为驱动表,大表作为被驱动表 。减少外层循环的次数。<br>④INNER JOIN 时,MySQL会自动将小结果集的表选为驱动表 。选择相信MySQL优化策略。<br>⑤能够直接多表关联的尽量直接关联,不用子查询。(减少查询的趟数)<br>⑦不建议使用子查询,建议将子查询SQL拆开结合程序多次查询,或使用 JOIN 来代替子查询。<br>⑥ 衍生表建不了索引<br>
子查询优化(不建议使用子查询)<br>
**子查询的执行效率不高。**原因:<br><br>① 执行子查询时,MySQL需要为内层查询语句的查询结果`<b>建立一个临时表</b>` ,然后外层查询语句从临时表<br>中查询记录。查询完毕后,`<b>再撤销这些临时表</b>` 。这样会`<b>消耗过多的CPU和IO资源</b>`,产生大量的慢查询。<br><br>② 子查询的结果集存储的临时表,不论是内存临时表还是磁盘`<b>临时表都不会存在索引</b>` ,所以查询性能会<br>受到一定的影响。<br><br>③ 对于返回结果集比较大的子查询,其对查询性能的影响也就越大。<br>
在MySQL中,可以使用连接(JOIN)查询来替代子查询。<b>连接查询不需要建立临时表 ,其速度比子查询 <br>要快 ,如果查询中使用索引的话,性能就会更好。</b><br><br><b>结论</b>:尽量不要使用NOT IN 或者 NOT EXISTS,用LEFT JOIN xxx ON xx WHERE xx IS NULL替代<br>
排序优化:<br>
<b><font color="#000000">-- 创建索引<br>CREATE INDEX idx_age_deptid_name ON emp (age,deptid,`name`);</font></b>
1. 无过滤,不索引<br>
-- 没有使用索引:<br><b><font color="#fc51fc">EXPLAIN SELECT</font><font color="#5c4038"> *</font><font color="#fc51fc"> FROM</font><font color="#5c4038"> emp</font><font color="#fc51fc"> ORDER BY </font><font color="#5c4038">age,deptid;</font><br></b><br>-- 使用了索引:order by想使用索引,必须有过滤条件,索引才能生效,limit也可以看作是过滤条件<br><b><font color="#fc51fc">EXPLAIN SELECT</font><font color="#5c4038"> * </font><font color="#fc51fc">FROM </font><font color="#5c4038">emp </font><font color="#fc51fc">ORDER BY </font><font color="#5c4038">age,deptid </font><font color="#fc51fc">LIMIT</font><font color="#5c4038"> 10;</font></b>
2. 顺序错,不索引<br>
-- 使用了索引:<br>-- 注意:key_len = 5是where语句使用age索引的标记,order by语句使用索引不在key_len中体现。<br><b><font color="#fc51fc">EXPLAIN SELECT </font><font color="#5c4038">*</font><font color="#fc51fc"> FROM </font><font color="#5c4038">emp</font><font color="#fc51fc"> WHERE</font><font color="#5c4038"> age=45 </font><font color="#fc51fc">ORDER BY </font><font color="#5c4038">deptid;</font></b><br><br>-- 使用了索引:<br><b><font color="#fc51fc">EXPLAIN SELECT </font><font color="#5c4038">*</font><font color="#fc51fc"> FROM </font><font color="#5c4038">emp </font><font color="#fc51fc">WHERE </font><font color="#5c4038">age=45 </font><font color="#fc51fc">ORDER BY </font><font color="#5c4038">deptid</font><font color="#fc51fc">, </font><font color="#ff0000">`</font><font color="#5c4038">name</font><font color="#ff0000">`; </font><br></b><br>-- 没有使用索引:因为索引列中不存在empno<br><b><font color="#fc51fc">EXPLAIN SELECT </font><font color="#5c4038">*</font><font color="#fc51fc"> FROM </font><font color="#5c4038">emp</font><font color="#fc51fc"> WHERE </font><font color="#5c4038">age=45 </font><font color="#fc51fc">ORDER BY </font><font color="#5c4038">deptid, empno;</font><br></b><br>-- 没有使用索引:order by 后的排序条件的顺序,与索引顺序不一致<br><b><font color="#fc51fc">EXPLAIN SELECT </font><font color="#5c4038">*</font><font color="#fc51fc"> FROM </font><font color="#5c4038">emp </font><font color="#fc51fc">WHERE </font><font color="#5c4038">age=45 </font><font color="#fc51fc">ORDER BY</font><font color="#5c4038"> </font><font color="#ff0000">`</font><font color="#5c4038">name</font><font color="#ff0000">`</font><font color="#5c4038">, deptid;</font><br></b><br>-- 没有使用索引:出现的顺序要和复合索引中的列的顺序一致!<br><b><font color="#fc51fc">EXPLAIN SELECT </font><font color="#5c4038">*</font><font color="#fc51fc"> FROM </font><font color="#5c4038">emp</font><font color="#fc51fc"> WHERE </font><font color="#5c4038">deptid=45 </font><font color="#fc51fc">ORDER BY</font><font color="#5c4038"> age;</font></b>
3. 方向反,不索引
-- 使用了索引:排序条件和索引一致,并方向相同,可以使用索引<br><font color="#fc51fc">SELECT </font><font color="#5c4038">*</font><font color="#fc51fc"> FROM </font><font color="#5c4038">emp</font><font color="#fc51fc"> WHERE </font><font color="#5c4038">age=45</font><font color="#fc51fc"> ORDER BY </font><font color="#5c4038">deptid</font><font color="#fc51fc"> DESC </font><font color="#000000">,</font><font color="#fc51fc"> </font><font color="#ff0000">`</font><font color="#5c4038">name</font><font color="#ff0000">` </font><font color="#fc51fc">DESC</font><font color="#000000">;</font><br><br>-- 没有使用索引:两个排序条件方向相反<br><font color="#fc51fc">SELECT </font><font color="#5c4038">* </font><font color="#fc51fc">FROM </font><font color="#5c4038">emp</font><font color="#fc51fc"> WHERE </font><font color="#5c4038">age=45</font><font color="#fc51fc"> ORDER BY</font><font color="#5c4038"> deptid </font><font color="#fc51fc">ASC </font><font color="#000000">,</font><font color="#fc51fc"> </font><font color="#ff0000">`</font><font color="#5c4038">name</font><font color="#ff0000">`</font><font color="#fc51fc"> DESC</font><font color="#000000">;</font>
SQL高级-慢查询日志于View视图
SQL高级-集群与分库分表
0 条评论
下一页