MySQL高级
Posted dxj1016
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL高级相关的知识,希望对你有一定的参考价值。
第 1 章 mysql 的架构介绍
1、MySQL 简介
1.1、概述
1.2、高级MySQL
- mysql内核
- sql优化工程师
- mysql服务器的优化
- 查询语句优化
- 主重复制
- 软硬件升级
- 容灾备份
- sql编程
2、MySQL逻辑架构简介
2.1、mysql的分层思想
- 和其它数据库相比,MySQL有点与众不同,它的架构可以在多种不同场景中应用并发挥良好作用。主要体现在存储引擎的架构上。
- 插件式的存储引擎架构将查询处理和其它的系统任务以及数据的存储提取相分离。这种架构可以根据业务的需求和实际需要选择合适的存储引擎。
2.2、mysql 四层架构
mysql四层架构
- 连接层:最上层是一些客户端和连接服务,包含本地sock通信和大多数基于客户端/服务端工具实现的类似于tcp/ip的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念,为通过认证安全接入的客户端提供线程。同样在该层上可以实现基于SSL的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作权限。
- 服务层:第二层架构主要完成大多数的核心服务功能,如SQL接口,并完成缓存的查询,SQL的分析和优化及部分内置函数的执行。所有跨存储引擎的功能也在这一层实现,如过程、函数等。在该层,服务器会解析查询并创建相应的内部解析树,并对其完成相应的优化如确定查询表的顺序,是否利用索引等,最后生成相应的执行操作。如果是select语句,服务器还会查询内部的缓存。如果缓存空间足够大,这样在解决大量读操作的环境中能够很好的提升系统的性能。
- 引擎层:存储引擎层,存储引擎真正的负责了MySQL中数据的存储和提取,服务器通过APl与存储引擎进行通信。不同的存储引擎具有的功能不同,这样我们可以根据自己的实际需要进行选取。后面介绍MyISAM和InnoDB
- 存储层:数据存储层,主要是将数据存储在运行于裸设备的文件系统之上,并完成与存储引擎的交互。
解析四层架构部件
-
connectors:不同语言中与sql的交互
-
connection pool:线程连接池
1. 管理缓冲用户连接,线程处理等需要缓存的需求。负责监听对 MySQL Server 的各种请求,接收连接请求,转发所有连接请求到线程管理模块。
2. 每一个连接上 MySQL Server 的客户端请求都会被分配(或创建)一个连接线程为其单独服务。而连接线程的主要工作就是负责 MySQL Server 与客户端的通信。接受客户端的命令请求,传递 Server 端的结果信息等。线程管理模块则负责管理维护这些连接线程。包括线程的创建,线程的 cache 等。 -
Management Services & Utilities:备份,容灾恢复,安全,复制,集群等。
-
SQL interface:SQL接口,接收用户的SQL命令,并返回用户需要查询的结果,比如select from就是调用SQL interface。存储过程,视图触发器等。
-
Parser:解析器,解析转换,sql语句加载从from开始,mysql将他重组过滤然后从from开始去解析。
1. 将SQL语句进行语义和语法的分析,分解成数据结构,然后按照不同的操作类型进行分类,然后做出针对性的转发到后续步骤,以后SQL语句的传递和处理就是基于这个结构的。
2. 如果在分解构成中遇到错误,那么就说明这个sql语句是不合理的 -
Optimizer:查询优化器,主人给我一个sql,是1,2,3,4顺序,但是我mysql会按照我自己认为最优的方式去执行,有可能我做了之后就是2,3,1,4执行顺序。但是这个并不是DBA程序员认为最优的sql方式去执行。如果极端业务的场景下,公司制定了优化方式让mysql按照他的方式执行,而不走mysql自己的优化步骤。所以后面如果出现索引失效可能就是这层优化器出现了问题。
-
Caches & Buffers:查询缓存,将返回结果cache到内存中,与该query的一个hash值做对比,数据发生变化后,自动让cache失效。读写多的系统中,性能提高显著,内存消耗也大。
-
引擎层:分层可拔插组件式的存储引擎,常用MyISAM和InnoDB;例子:去不同地理环境对跑车的路况,轮胎,底盘等不同,一种环境一种跑车成本太高;没办法一种环境一种车的情况下,一辆车去不同环境,就换掉车的引擎,这样更加优化经济。类似策略模式。==注意:存储引擎是基于表的,不是数据库。
-
存储层:file system:系统文件;files & logs:文件和日志。硬盘有关
2.3、查询语句的执行过程
查询语句的执行过程:
- 连接mysql服务器,发送查询语句
- 查询查询缓存,存在,则直接返回结果
- 语法解器和预处理,通过关键字对SQL语句解析并生成解析树,预处理器根据mysql规格进一步检查解析树是否合法。
- 解析树合法,由查询优化器将其转化为执行计划
- 查询执行计划
- 查询执行引擎
- 查询数据返回结果
3、存储引擎
3.1、查看 mysql 存储引擎
#查看mysql支持的存储引擎
mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine | Support | Comment | Transactions | XA | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO |
| MyISAM | YES | MyISAM storage engine | NO | NO | NO |
| CSV | YES | CSV storage engine | NO | NO | NO |
| ARCHIVE | YES | Archive storage engine | NO | NO | NO |
| PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO |
| FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
9 rows in set (0.00 sec)
#查看默认的存储引擎
mysql> show variables like '%storage_engine%';
+----------------------------------+--------+
| Variable_name | Value |
+----------------------------------+--------+
| default_storage_engine | InnoDB |
| default_tmp_storage_engine | InnoDB |
| disabled_storage_engines | |
| internal_tmp_disk_storage_engine | InnoDB |
+----------------------------------+--------+
4 rows in set, 1 warning (0.02 sec)
mysql>
3.2、MyISAM 和InnoDB的区别
- innodb是聚集索引,myisam是非聚集索引。
- 事务支持 > MyISAM:强调的是性能,每次查询具有原子性,其执行数度比 InnoDB 类型更快,但是不提供事务支持。 > InnoDB:提供事务支持事务,外部键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。
- InnoDB 支持行级锁,而 MyISAM 支持表级锁. >> 用户在操作myisam 表时,select,update,delete,insert 语句都会给表自动加锁,如果加锁以后的表满足 insert 并发的情况下,可以在表的尾部插入新的数据。
- InnoDB 支持 MVCC, 而 MyISAM 不支持
- InnoDB 支持外键,而 MyISAM 不支持
- 表主键 > MyISAM:允许没有任何索引和主键的表存在,索引都是保存行的地址。 > InnoDB:如果没有设定主键或者非空唯一索引,就自动生成一个 6 字节的主键(用户不可见),数据是主索引的一部分,附加索引保存的是主索引的值。
- InnoDB 不支持全文索引,而 MyISAM 支持。
- 可移植性、备份及恢复 > MyISAM:数据是以文件的形式存储,所以在跨平台的数据转移中会很方便。在备份和恢复时可单独针对某个表进行操作。 > InnoDB:免费的方案可以是拷贝数据文件、备份binlog,或者用 mysqldump,在数据量达到几十 G 的时候就相对痛苦了
- 存储结构 > MyISAM:每个 MyISAM 在磁盘上存储成三个文件。第一个文件的名字以表的名字开始,扩展名指出文件类型。.frm 文件存储表定义。数据文件的扩展名为.MYD (MYData)。索引文件的扩展名是.MYI (MYIndex)。 > InnoDB:所有的表都保存在同一个数据文件中(也可能是多个文件,或者是独立的表空间文件),InnoDB 表的大小只受限于操作系统文件的大小,一般为 2GB
第二章索引优化分析
4、索引
4.1、性能下降、 SQL 慢、执行时间长、等待时间长的原因分析
- 查询语句写的烂
- 索引失效:
- 单值索引:在user表中给name属性建个索引,create index idx_user_name on user(name)
- 复合索引:在user表中给name、email属性建个索引,create index idx_user_nameEmail on user(name,email)
- 关联查询太多join(设计缺陷或不得已的需求)
- 服务器调优及各个参数设置(缓冲、线程数等)
4.2、常见的Join查询
4.2.1、SQL 执行顺序
手写
机读
- FORM–执行顺序为从后往前、从右到左: 对FROM的左边的表和右边的表计算笛卡尔积。产生虚表VT1
- ON: 对虚表VT1进行ON筛选,只有那些符合的行才会被记录在虚表VT2中。
- JOIN: 如果指定了OUTER JOIN(比如left join、 right join),那么保留表中未匹配的行就会作为外部行添加到虚拟表VT2中,产生虚拟表VT3, rug from子句中包含两个以上的表的话,那么就会对上一个join连接产生的结果VT3和下一个表重复执行步骤1~3这三个步骤,一直到处理完所有的表为止。
- WHERE–执行顺序为自下而上、从右到左: 对虚拟表VT3进行WHERE条件过滤。只有符合的记录才会被插入到虚拟表VT4中。
- GROUP BY–执行顺序从左往右分组: 根据group by子句中的列,对VT4中的记录进行分组操作,产生VT5.
- CUBE | ROLLUP: 对表VT5进行cube或者rollup操作,产生表VT6.
- HAVING–很耗资源,尽量少用: 对虚拟表VT6应用having过滤,只有符合的记录才会被 插入到虚拟表VT7中。
- SELECT–少用*号,尽量取字段名称: 执行select操作,选择指定的列,插入到虚拟表VT8中。
- DISTINCT: 对VT8中的记录进行去重。产生虚拟表VT9.
- ORDER BY–执行顺序为从左到右排序,很耗资源: 将虚拟表VT9中的记录按照<order_by_list>进行排序操作,产生虚拟表VT10.
- LIMIT:取出指定行的记录,产生虚拟表VT11, 并将结果返回。
总结:mysql是从from开始执行的
4.2.2、Join查询
join图
select <select_list> from tableA A
inner join tableB B
on A.key=B.key;
select <select_list> from tableA A
left join tableB B
on A.key=B.key;
select <select_list> from tableA A
right join tableB B
on A.key=B.key;
select <select_list> from tableA A
left join tableB B
on A.key=B.key
where B.key is null;
select <select_list> from tableA A
right join tableB B
on A.key=B.key
where A.key is null;
select <select_list> from tableA A
full outer join tableB B
on A.key=B.key
select <select_list> from tableA A
full outer join tableB B
on A.key=B.key
where A.key is null
or B.key is null;
建表语句
#建库
create database db0629;
#使用建好的库
use db0629;
#建表
CREATE TABLE tbl_dept(
id INT(11) NOT NULL AUTO_INCREMENT,
deptName VARCHAR(30) DEFAULT NULL,
locAdd VARCHAR(40) DEFAULT NULL,
PRIMARY KEY(id)
)ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
#建表
CREATE TABLE tbl_emp (
id INT(11) NOT NULL AUTO_INCREMENT,
NAME VARCHAR(20) DEFAULT NULL,
deptId INT(11) DEFAULT NULL,
PRIMARY KEY (id),
KEY fk_dept_Id (deptId)
#CONSTRAINT 'fk_dept_Id' foreign key ('deptId') references 'tbl_dept'('Id')
)ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
#插入数据
INSERT INTO tbl_dept(deptName,locAdd) VALUES('RD',11);
INSERT INTO tbl_dept(deptName,locAdd) VALUES('HR',12);
INSERT INTO tbl_dept(deptName,locAdd) VALUES('MK',13);
INSERT INTO tbl_dept(deptName,locAdd) VALUES('MIS',14);
INSERT INTO tbl_dept(deptName,locAdd) VALUES('FD',15);
INSERT INTO tbl_emp(NAME,deptId) VALUES('z3',1);
INSERT INTO tbl_emp(NAME,deptId) VALUES('z4',1);
INSERT INTO tbl_emp(NAME,deptId) VALUES('z5',1);
INSERT INTO tbl_emp(NAME,deptId) VALUES('w5',2);
INSERT INTO tbl_emp(NAME,deptId) VALUES('w6',2);
INSERT INTO tbl_emp(NAME,deptId) VALUES('s7',3);
INSERT INTO tbl_emp(NAME,deptId) VALUES('s8',4);
INSERT INTO tbl_emp(NAME,deptId) VALUES('s9',51);
tbl_emp表的数据
mysql> select * from tbl_emp;
+----+------+--------+
| id | NAME | deptId |
+----+------+--------+
| 1 | z3 | 1 |
| 2 | z4 | 1 |
| 3 | z5 | 1 |
| 4 | w5 | 2 |
| 5 | w6 | 2 |
| 6 | s7 | 3 |
| 7 | s8 | 4 |
| 8 | s9 | 51 |
+----+------+--------+
8 rows in set (0.00 sec)
mysql>
tbl_dept表的数据
mysql> select * from tbl_dept;
+----+----------+--------+
| id | deptName | locAdd |
+----+----------+--------+
| 1 | RD | 11 |
| 2 | HR | 12 |
| 3 | MK | 13 |
| 4 | MIS | 14 |
| 5 | FD | 15 |
+----+----------+--------+
5 rows in set (0.00 sec)
inner join左表和右表共有部分
mysql> select * from tbl_emp a inner join tbl_dept b on a.deptid=b.id;
+----+------+--------+----+----------+--------+
| id | NAME | deptId | id | deptName | locAdd |
+----+------+--------+----+----------+--------+
| 1 | z3 | 1 | 1 | RD | 11 |
| 2 | z4 | 1 | 1 | RD | 11 |
| 3 | z5 | 1 | 1 | RD | 11 |
| 4 | w5 | 2 | 2 | HR | 12 |
| 5 | w6 | 2 | 2 | HR | 12 |
| 6 | s7 | 3 | 3 | MK | 13 |
| 7 | s8 | 4 | 4 | MIS | 14 |
+----+------+--------+----+----------+--------+
7 rows in set (0.00 sec)
left join左表全有
mysql> select * from tbl_emp a left join tbl_dept b on a.deptid=b.id;
+----+------+--------+------+----------+--------+
| id | NAME | deptId | id | deptName | locAdd |
+----+------+--------+------+----------+--------+
| 1 | z3 | 1 | 1 | RD | 11 |
| 2 | z4 | 1 | 1 | RD | 11 |
| 3 | z5 | 1 | 1 | RD | 11 |
| 4 | w5 | 2 | 2 | HR | 12 |
| 5 | w6 | 2 | 2 | HR | 12 |
| 6 | s7 | 3 | 3 | MK | 13 |
| 7 | s8 | 4 | 4 | MIS | 14 |
| 8 | s9 | 51 | NULL | NULL | NULL |
+----+------+--------+------+----------+--------+
8 rows in set (0.00 sec)
right join右表全有
mysql> select * from tbl_emp a right join tbl_dept b on a.deptid=b.id;
+------+------+--------+----+----------+--------+
| id | NAME | deptId | id | deptName | locAdd |
+------+------+--------+----+----------+--------+
| 1 | z3 | 1 | 1 | RD | 11 |
| 2 | z4 | 1 | 1 | RD | 11 |
| 3 | z5 | 1 | 1 | RD | 11 |
| 4 | w5 | 2 | 2 | HR | 12 |
| 5 | w6 | 2 | 2 | HR | 12 |
| 6 | s7 | 3 | 3 | MK | 13 |
| 7 | s8 | 4 | 4 | MIS | 14 |
| NULL | NULL | NULL | 5 | FD | 15 |
+------+------+--------+----+----------+--------+
8 rows in set (0.00 sec)
左表独有的
mysql> select * from tbl_emp a left join tbl_dept b on a.deptid=b.id where b.id is null;
+----+------+--------+------+----------+--------+
| id | NAME | deptId | id | deptName | locAdd |
+----+------+--------+------+----------+--------+
| 8 | s9 | 51 | NULL | NULL | NULL |
+----+------+--------+------+----------+--------+
1 row in set (0.04 sec)
右表独有的
mysql> select * from tbl_emp a right join tbl_dept b on a.deptid=b.id where a.deptid is null;
+------+------+--------+----+----------+--------+
| id | NAME | deptId | id | deptName | locAdd |
+------+------+--------+----+----------+--------+
| NULL | NULL | NULL | 5 | FD | 15 |
+------+------+--------+----+----------+--------+
1 row in set (0.00 sec)
左右表都有
部分代码片段
连接MySQL出现错误:ERROR 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using password: YES)(代码片段