MySQL
一,连接层功能:
1,TCP/IP或者Socket的链接方式
2,验证用户名密码功能
3,连接线程(客服):接收SQL语句,返回执行结果
二,SQL层
1,语法检查模块,检查上层发过来的SQL语句,进行语法检查
2,权限检查模块,检测当前登录用户是否有权限操作数据库对象
3,语义检查模块,识别语句种类
5,优化器,基于执行代价(系统资源的消耗作为维度(cpu、内存、IO),管理员可以通过间接的方法,干扰优化器的选择)
6,执行器,按照优化器选择的“最优”的执行计划,执行SQL语句。得出结论:某某磁盘的某某位置,发送给存储引擎层。
7,提供查询缓存:有局限性。一般会用Redis产品来替代
8,记录查询日志
SQL语句的分类:
DDL:数据定义语言
DCL:数据控制语言
DML:数据操作语言
DQL:数据查询语言
三,存储引擎层:
和“磁盘”(文件系统)打交道的层次
根据SQL层执行的结果,去磁盘上找到对应的数据。结构化成表的模式,返回给用户。
MySql逻辑结构组成:
一,库(库名字,库属性)
二,库(库名字,列(列名字,列属性)表属性,表数据)
MySQL索引
MySQL索引分类
存储引擎管理
一,索引管理以及原理
1,索引的种类
B树(B+tree B*tree b-tree)
B-tree:针对某个明确值的查询
查找顺序:根节点——>枝节点——>叶子节点
B+tree:针对明确的范围的查询
缺点:无法同时包含回表查询以及其它列的查询
辅助索引:(B TREE)
alter table t1 add index idx_num(telnum);
怎么生成的:
根据创建索引时,指定的列的值,进行排序后,存储在叶子节点中
优点:
1,优化了查询,减少CPU 内存 IO消耗
2,减少了文件排序
覆盖索引:(联合索引)
通过一个索引列把需要查询的列都添加到索引树里面去
直接在索引树里面直接有,减少或尽量避免回表查询操作
优点:减少回表查询的操作的几率
聚集索引 :
同一等级情况下效率最高
大部分情况下辅助索引和聚集索引结合使用
辅助索引:where 条件 有id列的时候,比如id=28
随机读 顺序读
建表时,如果有主键列,自动生成聚集索引
没有主键列,会去找unique列
优点:
减少回表查询
将随机IO转换成顺序IO
加强了缓存的应用,查询效率提升
2,R树
3,hash索引
4,全文索引
2,B树索引的类型
1,聚簇索引(cluster index):一般是基于主键的
2,辅助索引(普通辅助索引:回表查询;覆盖索引;不回表查询;唯一性索引)
3,唯一索引
3,索引管理
索引的作用:在mysql数据库中,索引是用来优化查询的
除缓存之外,数据的查询有两种方式:
1,全表扫描
2,索引扫描
优化器索引扫描要优于全表扫描
索引管理:
索引就是一张表
创建索引的语句:
为某张表基于某列建索引:alter table 表名 add index idx_name(列名)
MySQL不走索引的情况(开发规范)
重点关注:
1,没有查询条件,或者查询条件没有建立索引
select * from tab ;全表扫描
select * from tab where 1=1;
在业务数据库中,特别是数据库量比较大的表,是没有全表扫描这种需求的,当然我们也应该避免这种情况
1,对用户查看是非常痛苦的
2,对服务器来说是毁灭性的
(1) select * from tab
SQL改写成以下语句:
select * from tab order by price limit 10 ; 需要在price列上建立索引
(2) select * from tab where name=‘zhangsan'; name列没有索引
2,查询结果集是原表中的大部分数据,应该是25%以上。
查询的结果集,超过了总数行数25%,优化器就会觉得没有必要走索引了。
假如:tab表 id,name id:1-100w,id列有索引
select * from tab where id>50000;
3,索引本身失效,统计数据不真实
大量的操作插入删除操作,对表内容变化比较频繁的情况下,有可能会出现索引失效的情况。
4,查询条件使用函数在索引上,或者列进行计算,运算包括(+,-,*,/,!等)
算数运算
函数运算
子查询
例子:
错误的例子:select * from test where id-1=9;
正确的例子:select * from test where id=10;
5,隐式转换导致索引失效,这一点应当引起重视,也是开发中经常遇到会犯的错误!
6,<>,not in 不走索引
单独的 >,<,in有可能走,也有可能不走,和结果集有关,尽量结合业务添加limit
or或 in 尽量改成 union
7,like "%_"百分号在前面不走索引
%link%类的搜索需求,可以使用elasticsearch 专门做搜索服务的数据库产品
8,单独引用联合索引里非第一位置的索引列,作为条件查询时不走索引。
例子:
复合索引
DROP TABLE t1
CREATE TABLE t1(id INT,NAME VARCHAR(20),age INT , sex ENUM('m','f'),money INT );
ALTER TABLE t1 ADD INDEX t1_idx(money,age,sex);
DESC t1
SHOW INDEX FROM t1
走索引的情况测试:
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE money=30 AND age=30 AND sex='m';
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE money=30 AND age=30 ;
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE money=30 AND sex='m'; ----->部分走索引
不走索引的情况;
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE age=30;
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE age=30 AND sex='m';
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE sex='m';
MySQL存储引擎
查看存储引擎:
show engines;
show create table world.city;
插件式,即插即用存储引擎,是在表级别设定的。
mysql5.5以后默认的是InnoDB
InnoDB与MyISAM存储引擎的区别:
MVCC: innoDB支持,MyISAM不支持
锁(行级别): innodb支持,myisam表级别
外键: innodb支持,myisam不支持
事务: innodb支持,myisam不支持
热备份: innodb支持,myisam温备份
CSR(故障断电自动恢复)innodb支持,myisam不支持
InnoDB
MVCC
锁定粒度
外键
MyISAM
MEMORY(memory)
ARCHIVE(archive)
也可以使用第三方的存储引擎
TokuDB ------>zabbix
myrocks
InnoDB存储引擎的物理存储方式:
表空间(TBS)的管理模式:
来自于Oracle
表存储到磁盘上是以表空间的管理模式来存储
共享表空间:类似于Oracle管理模式
独立表空间:每个表单独使用表空间存储
5.5默认:共享表空间
5.6以后:默认管理模式独立表空间存储,共享表空间也存在
表空间存储数据的分类:
共享表空间:ibdata1
存了什么?
系统数据
undo日志
磁盘临时表
独立表空间:
t1.ibd ----->t1表的数据和索引
t1.frm ------>t1表的列相关信息
表空间操作:
共享表空间:
我们建议,在数据库初始化的时候就配置好
一般建议2-3个,512M
/etc/my.cnf
innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend
mysql_install_db
独立表空间:一个表一个ibd文件,存储表数据和索引
show variables like 'innodb_file_per_table';
事务
InnoDB存储引擎核心特性:
1,事务
简单来说:
事务会把业务流程中的多条语句放到一个执行(工作)单元里面,保证这多条语句要么全部成功,要么全部失败。
保证交易类业务完整性
官方:
一组数据操作执行步骤,这些步骤被视为一个工作单元
用于对多个语句进行分组
可以在多个客户机并发访问同一个表中的数据时使用
所有步骤都成功或者都失败
如果所有步骤正常,则执行
如果步骤出现错误或不完整,则取消
2,事务是保证数据的ACID特性
Atomic(原子性)
所有语句作为一个执行单元全部成功执行或全部取消执行。
保证了稳定性。
Consistent(一致性)
如果数据库在事务开始时处于一致状态,则在执行该VT事务期间将保留一致状态。
Isolated(隔离性)
事物之间不相互影响
Durable(持久性)
事务成功完成后,所做的所有更改都会准确地记录在VT数据库中,所做的更改不会丢,即使数据库宕机
3,标准的事务控制语句:
事务常见生命周期:
周期一:
begin; 开启事务
DML
DML
commit; 结束事务
周期二: 开启事务
begin;
DML
DML
rollback; 撤销事务
常识:MySQL5.5版本以后不需要自己手动来写begin语句,写DML语句时自动生成
注意:正常的遵循事务的ACID特性的事务,对于autocommit=1,需要手动关闭,默认等于1处于开启状态,自动提交功能
临时关闭,临时生效
set autocommit=0;
set global autocommit=0;
永久关闭
在my.cnf设置
autocommit=0;
4,隐式提交
用于隐式提交的SQL语句:
START TRANSACTION
SET AUTOCOMMIT = 1
导致提交的非事务语句:
DDL语句: ALTER、CREATE、DROP
DCL语句: GRANT、REVOKE、SET PASSWORD
锁定语句 LOCK TABLES 和 UNLOCK TABLES
导致隐式提交的语句:
TRUNCATE TABLES
LOAD DATA INFILE
SELECT FOR UPDATE
隐式提交的几种情况:
情况一:
begin
DML1
DML2
begin
情况二:
begin
DDL
DDL
情况三:
begin
DCL
DDL
5,innodb存储引擎物理存储层
表空间(t1.ibd)----->
段 一个表就是一个段(除了分区表)
区 连续的多个页
页 page(16KB)
每个数据页作为一个存储单元
6,存储引擎日志 -----物理层面
Redo:重做日志
Redo记录的是内存数据页的变化过程
Rudo:事务日志的一种,在事务ACID过程中,实现的是“D”持久化的作用,AC特性也和它有关
Rudo:CSR过程中实现前滚
存储位置:数据路径下存放,默认两个日志,默认标准大小50M,轮询覆盖形式使用文件日志
通过这两个参数控制,可以按照自己需求设定文件大小
innodb_log_file_size=50331648
innodb_log_files_in_group=2
ib_logfile0
ib_logfile1
查看标准大小:
mysql -uroot -p
show varables like '%log%';
LSN:日志序列号(也就是数据变化的版本号)
哪些地方会有日志序列版本号:
data page 磁盘数据页
logfile
data buffer
redo log buffer 日志的内存区域
数据库要求:启动时,必须保证data page 与logfile 中LSN号一致才能正常打开数据库,否则就会进行数据恢复
undo:回滚日志
undo记录了什么?
undo:记录数据页变化之前的数据状态以及TXID(数据页的id)
undo:事务日志的一种,在事务ACID过程中,实现的是“ACI”原子性,一致性的作用
undo作用:
1,rollback
2,CSR过程中实现回滚
事务没有进行commit提交的情况下:
先Rudo前滚
再undo回滚
四种隔离级别:
READ UNCOMMITTED 脏读
允许事务查看其他事务所进行的未提交更改
READ COMMITTED 幻读
允许事务查看其他事务所进行已提交更改
有可能出现幻读的现象,企业中坚决避免
REPEATABLE READ******可重复读,防止幻读现象
确保每个事务的SELECT 输出一致
InnoDB默认级别
SERIALIZABLE
将一个事务的结果与其他事务完全隔离
会阻塞其他事务的所有操作,只保证当前事务正常运行
Innodb事务锁机制
锁:顾名思义就是锁定的意思
种类:行级锁与表级锁
作用:在事务ACID过程中,锁和隔离级别一起来实现隔离性的作用
锁的粒度:
MyIasm:低并发锁 ——表级锁
InooDB:高并发锁 ——行级锁
事务出现冲突,出现锁争用:也名冲突事务
冲突事务例子:
例子:
1,事务1想要把a=1修改成a=2,,而这时事务2想要把a=1修改成a=3,这种情况下
2,两个事务同时更新一条数据
InnoDB体系结构扩展:
1,内存结构
2,线程结构
3,事务工作更详细流程
4,InnoDB存储引擎在安全和性能上的体现
5,Double Write
6,Db crash恢复流程
日志管理
1,错误日志
a,作用:
记录启动\关闭\日常运行过程中,状态信息,警告,错误
b,配置:
默认就是开启状态:/数据路径下/hostname.err
手动设定:
vim /etc/my.cnf
log_error=/var/log/mysql.log
重启生效:
show variables like 'log_error';
c,查看日志内容
主要关注[error],看上下文
2,二进制日志:binlog
1,作用:
1,备份恢复
2,主从环境
2,binlog配置(5.7必须加server_id)
vim /etc/my.cnf
server_id=6
log_bin=/data/mysql/mysql-bin
binlog_format=row
重启生效
注意:=/data/mysql 必须事先创建好,必须对mysql有权限
3,binlog记录了什么?
记录mysql数据库所有变更类的SQL语句
DDL,DCL,记录方式:SQL语句直接记录
DML记录三种方式: 只记录已经commit的DML
row 5.7默认
特点:记录数据行的变化,可读性不高,日志量较大,记录数据精确
statment 5.6默认
特点:可读性较高,日志量较少,但是以后恢复数据可能会是错误数据
mixed
4, event二进制的最小记录单元
对于DDL,DCL,一个事务就是一个event
对于DML,一个事务就被分为了四个event:
begin;
DML1
DML2
commit;
event组成:开始位置 + 事件内容 +结束位置
5,日志文件查看
log_bin参数设置的路径,可以找到二进制日志
show binary logs;
show master status;
6,日志内容查看
show master status;
show master status in 'mysql-bin.000002';
录入数据,看事件信息:
create database testdb;
create table t1(id int);
insert into t1 values(1);
commit;
show binlog events in 'mysql-bin.000002;
查看binlog文件详细内容:
mysqlbinlog /data/mysql/mysql-bin.000002;
mysqlbinlog --base64-output=decode-rows -vvvv /data/mysql/mysql-bin.000002;
mysqlbinlog -d testdb /data/mysql/mysql-bin.000002;
7,日志截取
mysqlbinlog --start-position --stop-position
恢复:
set sql_log_bin=0;
source /tmp/binlog.sql
set sql_log_bin=1;
8,二进制日志恢复数据
数据库的故障(损坏),原因:
1,软件损坏了
2,数据损坏了
3,硬件损坏,数据文件,数据页
4,逻辑损坏
5,SQL导致的误删除,误修改
只要拥有全量的binlog,就可以把数据库恢复到任意的时间点
3,慢日志(slow_log)
1,作用:
记录慢SQL语句的日志
2,开启慢日志,默认没开启
配置:
开启慢日志:
slow_query_log=1
文件位置以及名字:
slow_query_log_file=/data/mysql/slow.log
设定慢查询时间:
long_query_time=0.01
没走索引的语句也记录:
log_queries_not_using_indexes
服务器端配置,几条语句加进去就可以了
vim /etc/my.cnf
slow_query_log=1
slow_query_log_file=/data/mysql/slow.log
long_query_time=0.01
log_queries_not_using_indexes
/etc/init.d/mysql restart
3,分析慢日志
mysqldumpslow
mysqldumpslow -s c -t 10 /data/mysql/slow.log
备份恢复
1,备份类型
热备:在数据库正常业务是,备份数据,并且能够一致性恢复
冷备:关闭数据库业务,数据库没有任何变更的情况下,进行备份数据
温备:锁表备份,只能查询不能修改
2,备份方式,工具
逻辑备份:基于SQL语句进行备份:mysqldump,mysqlbinlog
物理备份:基于磁盘文件备份:cp,xtrabackup(XBK)
3,备份策略
1,全备:全库备份
2,增量:备份变化的数据
备份周期:多久全备,多久增量
4,恢复备份
5,故障恢复
6,迁移
主从复制
前提:
1,准备2个以上的mysql实例,有主有从
2,每台实例server_id不同
3,主库方面创建专用的复制用户
4,主库必须开启二进制日志
5,从库需要初始化数据,保证和主库数据在一个时间点上数据一致
1,搭建主从复制
1,准备多个mysql实例(3307(master),3308(slave1),3309(slave2))
具体环境配置文档(待QAQ续)
2,主库必须授权一个专门用作主从复制的用户
在创建一个复制用户
mysql -S /data/3307/mysql.sock
grant replication slave on *.* ro repl@'10.0.0.%' indextified by '123';
3,全备主库数据,恢复到从库
mysqldump -S /data/3307/mysql.sock -A -R --triggers --master-data=2 --single-transaction >/tmp/full.sql
mysql -S /data/3308mysql.sock
set sql_log_bin=0;
source /tmp/full.sql
4,开启主从复制
mysql -S /data/3308/mysql.sock
命令两条:
忘记了请记得让我们的help小姐姐来帮你QAQ: help change master to
CHANGE MASTER TO
MASTER_HOST='10.0.0.51', 填写主库ip
MASTER_USER='repl', 填写主库复制用户名
MASTER_PASSEORD='123', 填写主库复制用户密码
MASTER_[PORT=3307, 填写主库端口号
MASTER_LOG_FILE='mysql-bin.000001', 填写需要复制二进制日志名
MASTER_LOG_POS=325, 填写需要复制的二进制日志复制的起点
MASTER_CONNECT_RETRY=10; 重连重试次数
启动复制线程:
start slave;
查看主从状态:
show slave status \G
当你看到这两条命令为Yes,那么恭喜你成功了!
Slave_IO_Running:Yes
Slave_SQL_Running:Yes
2,主从复制存在原因
1,辅助备份
解决物理损坏
2,演变高可用架构
在主库发生故障时,自动进行故障转移,对于应用透明
3,演变高性能架构
读写分离
分布式
3,延时从库
4,过滤复制
控制过滤
从主库方面控制:复制指定的库到从库,对主库业务数据进行垂直拆分
从从库方面控制:只接收主库某个库复制过来的内容
1,从主库方面控制
show master status;
Binlog_Do_DB=白名单,在此参数中的库,记录二进制日志
Binlog_Ignore_DB=黑名单,在此参数中的库,不记录二进制日志
2,从库方面控制
Replicate_Do_DB: 白名单,在此参数中的库,复制
Replicate_Ignore_DB: 黑名单,在此参数中的库,不复制
Replicate_Do_Table: 白名单,在此参数中的表,复制
Replicate_Ignore_Table: 黑名单,在此参数中的表,不复制
模糊的表名字
Replicate_Wild_Do_Table: wolrd.t*
Replicate_Wild_Ignore_Table:
写法:
vim /data/3308/my.cnf
replicate_do_db=world
replicate_do_db=oldboy
5,主从复制之架构扩展GTID复制
1,环境准备
环境准备Centos拿db01克隆两台虚拟机
干掉原来数据库,并清理/application/mysql/data下所有数据,保证环境一致,干净
pkill mysqld
rm -rf /application/mysql/data*
1,备份三台机器/etc/my.cnf文件
mv/etc/my.cnf /tmp
2,书写配置文件:
master:10.0.0.51
vim/etc/my.cnf
[mysqld]
dasedir=/application/mysql
datadir=/application/mysql/data
socket=/tmp/mysql.sock
log-error=/var/log/mysql.log
log-bin=/data/mysql/mysql-bin
binlog_format=row
skip-name-resolve
server-id=51
gtid-more=on
enforce-gtid-consistency=true
log-slave-updates=1
[client]
socket=/tmp/mysql.sock
slave1:10.0.0.52
vim /etc/my.cnf
[mysqld]
dasedir=/application/mysql
datadir=/application/mysql/data
socket=/tmp/mysql.sock
log-error=/var/log/mysql.log
log-bin=/data/mysql/mysql-bin
binlog_format=row
skip-name-resolve
server-id=52
gtid-more=on
enforce-gtid-consistency=true
log-slave-updates=1
[client]
socket=/tmp/mysql.sock
slave2:10.0.0.53
vim /etc/my.cnf
[mysqld]
dasedir=/application/mysql
datadir=/application/mysql/data
socket=/tmp/mysql.sock
log-error=/var/log/mysql.log
log-bin=/data/mysql/mysql-bin
binlog_format=row
skip-name-resolve
server-id=53
gtid-more=on
enforce-gtid-consistency=true
log-slave-updates=1
[client]
socket=/tmp/mysql.sock
3,重新初始化三台机器数据
/application/mysql/scripts/mysql_install_db --basedir=/application/mysql/ --datadir=/application/mysql/data --user=mysql
4,分别启动三台数据库服务器
etc/init.d/mysqld start
2,GTID介绍
GTID是对于一个已提交事务的编号,并且是一个全局唯一的编号
官方定义:
GTID=source_id :transaction_id
7E11FA47-31CA-19E1-9E56-C43AA21293967:29
1,什么是sever_uuid和Server-id区别?
source_id 也叫uuid 默认是在第一次启动数据库时,自动生成的
/application/mysql/data/auto.cnf
手动删除掉此文件,重启数据库,可以生成新的
2,重要参数
gtid-mode=on --启动gtid类型,否则就是普通的复制架构
erforce-gtid-consistency=true --强制GTID的一致性
log-slave-updates=1 --slave更新是否记入日志
3,基于GTID的复制构建
master:51
slave:52,53
51:
grant replication slave on *.* to repl@'10.0.0.%' identified by '123';
52\53:
source bak.sql
change master to msater_host ='10.0.0.51',master_user='repl',master_password='123',MASTER_AUTO_POSITION=1;
start slave;
change master to msater_host ='10.0.0.51',master_user='repl',master_password='123',MASTER_AUTO_POSITION=1;
高可用以及读写分离
分布式系统