mysql/MySQL.md

3225 lines
112 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# MySQL
什么是数据库 有什么用 生产环境
sql语句 基本的增删改查
数据库管理
权限管理
日志管理
备份数据
恢复数据
集群AB复制 集群部署)
结绳
骨头
竹简
丝绸
纸张
文件
数据库 使用结构化的查询语言读写数据 sql
大量同类型的数据 读 写
大数据
数据库分类
关系型数据库
有库 有表 字段 记录
非关系型数据库 nosql
分布式数据库
一台服务器
集群 节点
set a 8
a 键key
8 值value
get a
b="a"
b=a
## 数据的存储方式
1. 人工管理阶段
2. 文件系统阶段
3. 数据库系统管理阶段
4. 大数据 BIG DATA
## 数据库技术构成
1. 数据库系统 DBS
A.数据库管理系统DataBase Management System DBMS:
SQL(RDS): ORACLE、Oracle MySQL、MariaDB、Percona server、DB2
NoSQL: Redis、MongoDB、Memcache
B.DBA
2. SQL语言结构化查询语言
A. DDL语句 数据库定义语言: 数据库、表、视图、索引、存储过程、函数, CREATE DROP ALTER //开发人员
B. DML语句 数据库操纵语言: 插入数据INSERT、删除数据DELETE、更新数据UPDATE //开发人员
C. DQL语句 数据库查询语言: 查询数据 **SELECT**
D. DCL语句 数据库控制语言: 例如控制用户的访问权限GRANT、REVOKE
3. 数据访问技术
A. ODBC PHP <.php>
B. JDBC JAVA <.jsp>
API接口 应用程序接口
## MySQL介绍
去IOE运动
oracle
mariadb
MySQL的早期创始人之一MontyWidenius是公开反对Sun与甲骨文合并的著名人士之一。他2009年离开Sun后创办了Monty ProgramAB公司并开发出了MariaDB—这是一种新版本的MySQL这家公司的产品立足于MariaDB开源数据库
NoSQL能替代MySQL吗
市场上有许多小的"MySQL",这些开源的、比较简单、快速的数据库统一称为“NoSQL”。这些产品与早期的MySQL一样很有特点但难免稚嫩。
  当然Oracle很聪明认识到自己的要求得有个“度”不然用户会开始改写代码。比如说Twitter已宣布大范围尝试改用Cassandra来开发基础架构。Cassandra是另一种开源项目采用更加开放的Apache许可证。
  Twitter的举措也许纯粹出于技术上的考虑:Cassandra是一种非常简单、快速的数据库没有很多比较复杂的保护措施比如事务处理。Twitter这一举措的意义在于它可能为不想陷入许可困境的MySQL用户指明一条更省事的道路。实际上还有众多像Cassandra这样的项目它们都常常用“NoSQL”这个流行词来定义。不过采用NoSQL是要付出代价的。
  NoSQL显然有一席之地但它不适合普通的开发人员因为NoSQL在某些方面为你提升性能的同时却在其他很多方面降低了灵活性和兼容性。Widenius说“它让我想起了MySQL问世之前存在的众多数据库。MySQL开始流行后这些数据库先后退出了市场原因是MySQL很容易使用极容易与其他应用软件进行连接这归功于SQL接口。”
  的确今天的NoSQL数据库让人联想到了MySQL昔日的境况。与Cassandra一样MySQL数据库也是从一个很小的项目做起来的它摈弃了最传统的数据库拥有的一些保护措施因而提供了非常快的存储性能。之后MySQL逐渐添加了很多其他方面的功能成为了一款成功的数据库产品能够处理一些比较高端的事务所有这些工作原本都需要更多的工程师和更多的预算。
  实际上Widenius以及高度依赖MySQL的企业现在处境很微妙。如果MariaDB因潜在客户想规避许可问题而失败留给他的将是一家倒闭公司不过那可以证明他预测Oracle与Sun合并案会带来不利影响是正确的;如果MariaDB生意兴隆他可能会享受这种成功带来的喜悦但他的预测肯定会受到更多人的怀疑。在一条道路上他成为击败巨人歌利亚Oracle的大卫;而在另一条道路上他将被视做预言家卡珊德拉希腊神话中的预言家预言很准但没人信她。不管怎样Widenius肯定会既是正确的也是错误的。
  人们对MySQL的未来担心主要有两个:一个是Oracle未来可能不给MySQL继续投入让其自生自灭;另一个是Oracle可能会改变MySQL的销售策略。如果出现这两种结果中的任何一种最终都会导致数据库市场竞争的减少使得用户利益受损。现在看来短期内MySQL不太可能落到这样的命运。其中很重要的一个原因是MySQL的销售将采用GPL授权。
  在不久前举办的O'Reilly MySQL大会上MySQL社区副总裁Kaj Arno公开表示MySQL将继续采用GPL授权。如果MySQL采用GPL对MySQL会起到一定保护作用。
  首先众所周知GPL授权的核心是如果某产品是基于GPL授权的开源产品开发那么该产品也必须公开源码并采用GPL授权。由于GPL的这一规定Oracle不能将MySQL变为闭源产品销售。
  其次如果Oracle停止对MySQL投入只要市场存在对这类开源数据库的需求现在已经存在的MySQL的衍生版如Drizzle、MariaDB可能很快会顶替MySQL的位置其他组织也可以根据GPL授权推出新类型的MySQL版本如NoSQL。这种局面肯定不会是Oracle愿意看到的对于Oracle来说与其培育一个新的竞争对手显然不如把这个竞争对手拉入自己的阵营。更何况短期内放弃MySQL对Oracle而言还面临着巨大的公关压力。
之前的MySQL公司一直坚持自己拥有完整的版权其办法是要求所有开发人员签署将版权授予该公司的协议。这种权利意味着只有MySQL才能销售商用软件证而不用GPL。用户采用GPL许可的麻烦在于GPL是一种让人迷惑的许可方式其细节非常复杂。有些人认为该许可证更适用于设备驱动程序以及用来定义连接的协议。
MySQL从开发人员手中的“玩具”变为如今的“世界上最流行的开源数据库”其中的过程伴随着产品版本升级以及一些新功能特别是企业数据库功能的增加。现在随着MySQL 5.0被完美地开发出来已经很少有人将MySQL称为“玩具数据库”了。MySQL的丰富功能满足了许多用户的需求Oracle最近的动作表明了他们对待MySQL非常重视——Oracle曾几次三番的表示有意收购MySQL。
**MySQL的产品路线图**
让我们先从MySQL的较有影响的版本产品开始看一下MySQL的更新换代。
MySQL 4.0
  MySQL 4.0是在2003年3月发布的该版本使新的基于MySQL的应用程序获得了更广泛的应用。但是在4.0版中MySQL不支持存储过程、触发程序、服务器端指针或视图。MySQL 4.0是从3.23发展而来较之3.23版本有了很大的提高主要适用于Web站点这时候的MySQL还不是一个企业级数据库。
MySQL 5.0 2005年年初
  支持存储过程。存储过程是一个开发人员在其他数据库环境最常用的ANSI SQL标准对于MySQL来说这已经姗姗来迟了。MySQL 5.0所支持的存储过程的语法类似于Oracle PL/SQL和T-SQL。
  触发程序(发生某个事件时所称的存储过程)
  支持指针
  真正支持VARCHAR数据类型解决了一个长期存在的MySQL VARCHAR bug。
在MyISAM表中对RTREE索引的支持将使访问地理数据变得很容易。
MySQL是一个小型关系型数据库管理系统开发者为瑞典MySQL AB公司。在2008年1月16号被Sun公司收购。而2009年SUN又被Oracle收购。对于Mysql的前途没有任何人抱乐观的态度。目前MySQL被广泛地应用在Internet上的中小型网站中。由于其体积小、速度快、总体拥有成本低尤其是开放源码这一特点许多中小型网站为了降低网站总体拥有成本而选择了MySQL作为网站数据库。
MySQL最初的开发者的意图是用mSQL和他们自己的快速低级例程(ISAM)去连接表格。不管怎样在经过一些测试后开发者得出结论mSQL并没有他们需要的那么快和灵活。这导致了一个使用几乎和mSQL一样的API接口的用于他们的数据库的新的SQL接口的产生这样这个API被设计成允许为用于mSQL而写的第三方代码更容易移植到MySQL。
  MySQL这个名字是怎么来的已经不清楚了。基本指南和大量的库和工具带有前缀“my”已经有10年以上而且不管怎样MySQL AB创始人之一的 MySQL AB创始人之一Monty Widenius的女儿也叫My。这两个到底是哪一个给出了MySQL这个名字至今依然是个迷包括开发者在内也不知道。
MySQL的海豚标志的名字叫“sakila”它是由MySQL AB的创始人从用户在“海豚命名”的竞赛中建议的大量的名字表中选出的。获胜的名字是由来自非洲斯威士兰的开源软件开发者Ambrose Twebaze提供。根据Ambrose所说Sakila来自一种叫SiSwati的斯威士兰方言也是在Ambrose的家乡乌干达附近的坦桑尼亚的Arusha的一个小镇的名字。
MySQL是一种数据库管理系统
数据库是数据的结构化集合。它可以是任何东西从简单的购物清单到画展或企业网络中的海量信息。要想将数据添加到数据库或访问、处理计算机数据库中保存的数据需要使用数据库管理系统如MySQL服务器。计算机是处理大量数据的理想工具因此数据库管理系统在计算方面扮演着关键的中心角色或是作为独立的实用工具或是作为其他应用程序的组成部分。
MySQL是一种关联数据库管理系统
关联数据库将数据保存在不同的表中而不是将所有数据放在一个大的仓库内。这样就增加了速度并提高了灵活性。MySQL的SQL指得是“结构化查询语言”。SQL是用于访问数据库的最常用标准化语言它是由ANSI/ISO SQL标准定义的。SQL标准自1986年以来不断演化发展有数种版本。在本手册中“SQL-92”指得是1992年发布的标准“SQL:1999”指得是1999年发布的标准“SQL:2003”指得是标准的当前版本。我们采用术语“SQL标准”标示SQL标准的当前版本。
MySQL软件是一种开放源码软件
“开放源码”意味着任何人都能使用和改变软件。任何人都能从Internet下载MySQL软件而无需支付任何费用。如果愿意你可以研究源码并进行恰当的更改以满足你自己的需求。MySQL软件采用了GPLGNU通用公共许可证定义了在不同情况下可以用软件作的事和不可作的事。数据库服务器具有快速、可靠和易于使用。MySQL服务器还有一套实用的特性集合在基准测试主页上给出了MySQL服务器和其他数据库管理器的比较结果。
## MySQL安装方式
**RPM**
优点 安装简单
缺点 需要单独下载客户端和服务器安装路径不灵活默认路径不能修改一台服务器只能装一个mysql
**二进制**
优点: 安装简单可以安装到任何路径下灵活性好一台服务器可以安装多个mysql
缺点: 已经编译好,性能不如源码编译;不能灵活定制编译参数
**源码**
优点: 可根据实际环境需求定制编译参数最灵活一台服务器可以安装多个mysql
缺点: 安装过程较复杂,编译时间较长
## RPM安装
**配置安装源**
官方yum源
```http
官方地址http://dev.mysql.com/doc/refman/5.7/en/linux-installation-yum-repo.html
下载软件mysql57-community-release-el7-9.noarch.rpm
注意:现在直接下载最新版(现在是8.0版)的Yum源安装包安装完后修改yum源配置文件为5.7即可
# yum -y install mysql57-community-release-el7-9.noarch.rpm
```
国内yum源
```bash
[root@localhost yum.repos.d]# vim mysql.repo
[mysql]
name=mysql
baseurl=https://mirrors.tuna.tsinghua.edu.cn/mysql/yum/mysql-5.7-community-el7-x86_64/
gpgcheck=1
enabled=1
gpgkey=https://mirrors.ustc.edu.cn/mysql-repo/RPM-GPG-KEY-mysql
```
**安装软件**
```bash
# yum repolist enabled | grep mysql
# yum -y install mysql-community-server
# systemctl start mysqld //第一次启动会自动始化数据库
# systemctl enable mysqld
# grep password /var/log/mysqld.log
```
**修改密码**
5.7默认有临时密码,需要修改,两种方式:
第一种
```mysql
# mysql -uroot -p'uopCBgXBu8,k'
mysql> alter user 'root'@'localhost' identified by 'Qianfeng123!@';
```
第二种
```bash
# mysqladmin -u root -p'uopCBgXBu8,k' password 'Qianfeng123!@'
```
**关闭弱密码限制**
```bash
rpm安装的5.7如下方式修改
# vim /etc/my.cnf
validate_password=off
编译安装的5.7如下方式修改
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
[mysqld_safe]
validate_password=off
```
## SQL语言介绍
SQLStructured Query Language 即结构化查询语言)
SQL语言主要用于存取数据、查询数据、更新数据和管理关系数据库系统SQL语言由IBM开发。
DDL语句 数据库定义语言: 数据库、表、视图、索引、存储过程例如CREATE DROP ALTER
DML语句 数据库操纵语言: 插入数据INSERT、删除数据DELETE、更新数据UPDATE
DCL语句 数据库控制语言: 例如控制用户的访问权限GRANT、REVOKE
DQL语句 数据库查询语言: 查询数据SELECT
| 操纵 |
| -------------------------------- |
| manipulation 英[məˌnɪpjʊˈleɪʃən] |
## 库操作
**系统数据库**
information_schema
虚拟库,主要存储了系统中的一些数据库对象的信息,例如用户表信息、列信息、权限信息、字符信息等
performance_schema
主要存储数据库服务器的性能参数
mysql
授权库,主要存储系统用户的权限信息
sys
主要存储数据库服务器的性能参数
**创建数据库3种方法**
```bash
1. # mysqladmin -u root -p1 create db1
2. 直接去创建数据库目录并且修改权限 # 不建议使用
3. mysql> create database wing; #wing是数据库名称
```
**数据库命名规则**
区分大小写
唯一性
不能使用关键字如 create select
不能单独使用数字
**sql语句结尾**
每条sql语句都要以;结尾,但是如果列比较多,想看的清楚一点,可以以\G结尾
**查看数据库**
```sql
mysql> show databases;
mysql> show create database wing;
```
**查看当前所在库**
```sql
mysql> select database();
```
**切换数据库**
```sql
mysql> use wing;
mysql> show tables;
```
**删除数据库**
```sql
mysql> drop database 数据库名;
```
## 表操作
**表**是数据库存储数据的基本单位,由若干个字段组成,主要用来存储数据记录。
**使用编辑器编辑指令**
```sql
mysql> edit
mysql> \e
```
**在mysql客户端内执行系统命令**
```sql
mysql> system ls
mysql> \! ls
```
**创建表**
表名:school.student1
| 字段名称 | id | name | sex | age |
| -------- | ---- | ----- | ------ | ---- |
| 记录 | 1 | tom | male | 23 |
| 记录 | 2 | jack | male | 21 |
| 记录 | 3 | alice | female | 19 |
**语法**
```sql
mysql > create table 表名(
字段名1 类型[(宽度) 约束条件],
字段名2 类型[(宽度) 约束条件],
字段名3 类型[(宽度) 约束条件]
)[存储引擎 字符集];
在同一张表中,字段名是不能相同
宽度和约束条件可选
字段名和类型是必须的
```
```sql
mysql> CREATE DATABASE school
mysql> use school;
mysql> create table student1(
-> id int,
-> name varchar(50),
-> sex enum('m','f'),
-> age int
-> );
Query OK, 0 rows affected (0.03 sec)
```
**查看表(当前所在库)**
```sql
mysql> show tables;
mysql> desc emp;
mysql> show create table emp;
mysql> show table status like 'emp' \G
```
**修改表名称**
```sql
mysql> rename table emp to abc;
mysql> alter table abc rename emp;
```
**查看表内容**(后面单独讲表查询操作)
```sql
mysql> select * from student1; //查询表中所有字段的值
mysql> select name,age from student1; //查询表中指定字段的值
```
**字段操作**
```sql
添加新字段
mysql> alter table t1 add math int(10);
mysql> alter table t1 add (chinese int(10),english int(10));
修改字段数据类型、修饰符
mysql> alter table t1 modify chinese int(5) not null;
修改名称、数据类型、修饰符
mysql> alter table t1 change chinese china int(6);
first after
mysql> alter table t1 change english en int(6) after id;
mysql> alter table t1 modify en int(6) first;
删除字段
mysql> alter table t1 drop en;
```
**记录操作**
```sql
插入数据(添加记录)
字符串必须引号引起来
mysql> insert into t1(id,name,math,china) values(1,"wing",80,90);
mysql> insert into t1(id,name,math,china) values(2,"king",70,100),(3,"tom",50,70);
mysql> insert into t1 values(4,"xiaosan",50,100);
mysql> insert into t1(id,math) values(5,70);
mysql> insert into t1 set id=6,math=65;
更新记录
mysql> update t1 set name="lili" where id=5;
删除记录
mysql> delete from t1 where id=6;
mysql> delete from t1; //删除所有记录
```
**表复制**key不会被复制: 主键、外键和索引
```sql
复制一张表
mysql> create table t10(select * from t3);
mysql> create table t10(select id,name from t3);
复制表结构
mysql> create table t4(select * from t3 where 5=4);
mysql> create table t4(select id,name from t3 where 5=4);
复制记录
mysql> insert into t3 select * from t10 where id=9;
```
**删除表**
```sql
删除单张表
mysql> drop table t1;
删除多张表
mysql> drop table t1,t2,t3;
```
## 单表查询
**测试表设计**
表名称:
company.employee5
表结构:
```ini
雇员编号 id int
雇员姓名 name varchar(30)
雇员性别 sex enum
雇用时期 hire_date date
职位 post varchar(50)
职位描述 job_description varchar(100)
薪水 salary double(15,2)
办公室 office int
部门编号 dep_id int
```
**测试表创建**
```sql
mysql> CREATE TABLE company.employee5(
id int primary key AUTO_INCREMENT not null,
name varchar(30) not null,
sex enum('male','female') default 'male' not null,
hire_date date not null,
post varchar(50) not null,
job_description varchar(100),
salary double(15,2) not null,
office int,
dep_id int
);
mysql> insert into company.employee5(name,sex,hire_date,post,job_description,salary,office,dep_id) values
('jack','male','20180202','instructor','teach',5000,501,100),
('tom','male','20180203','instructor','teach',5500,501,100),
('robin','male','20180202','instructor','teach',8000,501,100),
('alice','female','20180202','instructor','teach',7200,501,100),
('wing','male','20180202','hr','hrcc',600,502,101),
('harry','male','20180202','hr',NULL,6000,502,101),
('emma','female','20180206','sale','salecc',20000,503,102),
('christine','female','20180205','sale','salecc',2200,503,102),
('zhuzhu','male','20180205','sale',NULL,2200,503,102),
('gougou','male','20180205','sale','',2200,503,102);
```
**简单查询**
```sql
mysql> select * from t3;
mysql> select name, salary, dep_id from employee5;
```
**避免重复DISTINCT**
```sql
mysql> SELECT post FROM employee5;
mysql> SELECT DISTINCT post FROM employee5;
注:不能部分使用DISTINCT,通常仅用于某一字段。
```
**通过四则运算查询**
```sql
mysql> select math*china-50 from t1; nginx.conf
mysql> select 437.4384/5
mysql> select 5>3;
mysql> SELECT name, salary, salary*14 FROM employee5;
mysql> SELECT name, salary, salary*14 AS Annual_salary FROM employee5;
mysql> SELECT name, salary, salary*14 Annual_salary FROM employee5;
mysql> SELECT name, salary, salary*14 "Annual salary" FROM employee5;
```
**定义显示格式**
```sql
CONCAT() 函数用于连接字符串
mysql> SELECT CONCAT(name, ' annual salary: ', salary*14) AS Annual_salary FROM employee5;
```
**单条件查询**
```sql
mysql> select pass from t3 where name="wing";
```
**多条件查询**
```sql
mysql> select math from db1.t1 where math>50 and math<600
mysql> mysqlselect math from db1.t1 where not math>50;
```
**关键字BETWEEN AND**
```sql
mysql> SELECT name,salary FROM employee5
WHERE salary BETWEEN 5000 AND 15000;
mysql> SELECT name,salary FROM employee5
WHERE salary NOT BETWEEN 5000 AND 15000;
```
**关键字IS NULL**
```sql
mysql> SELECT name,job_description FROM employee5
WHERE job_description IS NULL;
mysql> SELECT name,job_description FROM employee5
WHERE job_description IS NOT NULL;
mysql> SELECT name,job_description FROM employee5
WHERE job_description='';
NULL说明
1、等价于没有任何值、是未知数。
2NULL与0、空字符串、空格都不同,NULL没有分配存储空间
3、对空值做加、减、乘、除等运算操作,结果仍为空。
4、比较时使用关键字用"is null""is not null"
5、排序时比其他数据都小(索引默认是降序排列,小→大),所以NULL值总是排在最前
id=null
id=""
1k 2k 4k
a.txt
```
**关键字IN集合查询**
```sql
mysql> SELECT name, salary FROM employee5
WHERE salary=4000 OR salary=5000 OR salary=6000 OR salary=9000 ;
mysql> SELECT name, salary FROM employee5
WHERE salary IN (4000,5000,6000,9000) ;
mysql> SELECT name, salary FROM employee
WHERE salary NOT IN (4000,5000,6000,9000) ;
```
**排序查询**
```sql
mysql> select china from t1 order by china;
mysql> select china from t1 order by china desc;
mysql> select china from t1 order by china desc limit 3;
mysql> select china from t1 order by china desc limit 1,3;
注:
ascending 美音 /ə'sɛndɪŋ/ 升序
descending 美音 /dɪ'sɛndɪŋ/ 降序
```
按多列排序
**入职时间相同的人薪水不同**
mysql> SELECT * FROM employee5
ORDER BY hire_date DESC,salary ASC;
[![file://C:/Users/86186/AppData/Local/Temp/.SRP311/1.png](assets/1-16789386892061.png)]()
**先按入职时间,再按薪水排序**
[![file://C:/Users/86186/AppData/Local/Temp/.SRP311/2.png](assets/2-16789386892072.png)]()
**先按职位,再按薪水排序**
[![file://C:/Users/86186/AppData/Local/Temp/.SRP311/3.png](assets/3-16789386892073.png)]()
**限制查询的记录数**
```sql
mysql> SELECT * FROM employee5 ORDER BY salary DESC
LIMIT 5; //默认初始位置为0
mysql> SELECT * FROM employee5 ORDER BY salary DESC
LIMIT 0,5;
mysql> SELECT * FROM employee5 ORDER BY salary DESC
LIMIT 3,5; //从第4条开始,共显示5
```
**分组查询**
```sql
mysql> select count(gender),gender from t3 group by gender;
GROUP BY和GROUP_CONCAT()函数一起使用
mysql> SELECT dep_id,GROUP_CONCAT(name) FROM employee5 GROUP BY dep_id;
mysql> SELECT dep_id,GROUP_CONCAT(name) as emp_members FROM employee5 GROUP BY dep_id;
```
[![file://C:/Users/86186/AppData/Local/Temp/.SRP311/4.png](assets/4.png)]()
![image-20230316121550110](assets/image-20230316121550110-16789401570074.png)
**GROUP BY和集合函数一起使用**
[![file://C:/Users/86186/AppData/Local/Temp/.SRP311/6.png](assets/6.png)]()
**模糊查询**(通配符)
```sql
_ 任意单个字符
% 所有字符
mysql> select * from t1 where china='1__';
mysql> select * from t1 where china like '%0%';
```
**正则查询**
```sql
mysql> select * from t1 where china regexp '10+';
mysql> SELECT * FROM employee5 WHERE name REGEXP '^ali';
mysql> SELECT * FROM employee5 WHERE name REGEXP 'yun$';
mysql> SELECT * FROM employee5 WHERE name REGEXP 'm{2}';
```
**子查询**
```sql
mysql> select name from t2 where math=(select max(math) from t2);
```
![image-20230316121523929](assets/image-20230316121523929.png)
**查询函数**
```sql
count()
max()
min()
avg()
database()
user()
now()
sum()
上面的函数全部c
password()
md5()
sha1()
power()
```
**例子**
```sql
SELECT COUNT(*) FROM employee5;
SELECT COUNT(*) FROM employee5 WHERE dep_id=101;
SELECT MAX(salary) FROM employee5;
SELECT MIN(salary) FROM employee5;
SELECT AVG(salary) FROM employee5;
SELECT SUM(salary) FROM employee5;
SELECT SUM(salary) FROM employee5 WHERE dep_id=101;
MariaDB [company]> select password(5);
+-------------------------------------------+
| password(5) |
+-------------------------------------------+
| *7534F9EAEE5B69A586D1E9C1ACE3E3F9F6FCC446 |
+-------------------------------------------+
MariaDB [company]> select md5(5);
+----------------------------------+
| md5(5) |
+----------------------------------+
| e4da3b7fbbce2345d7772b0674a318d5 |
+----------------------------------+
1 row in set (0.00 sec)
MariaDB [company]> select sha1(5);
+------------------------------------------+
| sha1(5) |
+------------------------------------------+
| ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4 |
+------------------------------------------+
1 row in set (0.00 sec)
```
POWER() function
MySQL POWER() returns the value of a number raised to the power of another number. The synonym of POWER() is POW().
[![file://C:/Users/86186/AppData/Local/Temp/.SRP311/8.png](assets/8.png)]()
```sql
mysql> SELECT POWER(3, 2);
+-------------+
| POWER(3, 2) |
+-------------+
| 9 |
+-------------+
1 row in set (0.00 sec)
```
## 数据类型
在MySQL数据库管理系统中可以通过存储引擎来决定表的类型。同时MySQL数据库管理系统也提供了数据类型决定表存储数据的类型。
**常见的数据类型**
数值类型:
整数类型 TINYINT SMALLINT MEDIUMINT INT BIGINT
浮点数类型 FLOAT DOUBLE
定点数类型 DEC
位类型 BIT
字符串类型:
CHAR系列 CHAR VARCHAR
TEXT系列 TINYTEXT TEXT MEDIUMTEXT LONGTEXT
BLOB 系列 TINYBLOB BLOB MEDIUMBLOB LONGBLOB
BINARY系列 BINARY VARBINARY
枚举类型: ENUM
集合类型: SET
时间和日期类型: DATE TIME DATETIME TIMESTAMP YEAR
### 数值类型
**整型**
作用用于存储用户的年龄、游戏的Level、经验值等。
两种类型分类:
分类1tinyint smallint mediumint int bigint
```ini
存储数据大小范围:
tinyint smallint mediumint int bigint
1个字节Byte 2个字节 3个字节 4个字节 8个字节
8bit 16bit 24bit 32bit 64bit
```
分类2有符号 无符号
有符号
有正负数
范围运算公式 -2^(n-1)到2^(n-1)-1
比如:
tinyint:-128到127
无符号
范围运算公式 0到2^n-1
比如:
tinyint:0到255
bigint: 0到2^64-1
没有负数 类型后面使用unsigned和zerofill修饰符
**显示宽度(8.0被砍掉,不用管了)**
类型后面小括号内的数字是显示宽度,不能限制插入数值的大小
比如bigint(2) 2是显示宽度,跟zerofill配合才能看出效果
**定义无符号整型有两种方法unsigned和zerofill**
```sql
unsigned:
mysql> create table t6(id bigint unsigned);
zerofill:
mysql> create table t2 (
-> id1 int zerofill,
-> id2 int(6) zerofill
-> );
Query OK, 0 rows affected (0.05 sec)mysql> desc t2;
+-------+---------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------------+------+-----+---------+-------+
| id1 | int(10) unsigned zerofill | YES | | NULL | |
| id2 | int(6) unsigned zerofill | YES | | NULL | |
+-------+---------------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> insert into t2 values(2,2);
Query OK, 1 row affected (0.01 sec)
mysql> select * from t2;
+------------+--------+
| id1 | id2 |
+------------+--------+
| 0000000002 | 000002 |
+------------+--------+
1 row in set (0.00 sec)
```
**浮点型**
作用:用于存储用户的身高、体重、薪水等
float(5,3) 5宽度 3精度
```sql
mysql> create table t12(id float(6,2));
```
double(5,3)
**定点型**
定点数在MySQL内部以字符串形式存储比浮点数更精确适合用来表示货币等精度高的数据。
decimal(5,3)
**位类型**(了解)
BIT(M)可以用来存放多位二进制数M范围从1~64如果不写默认为1位
对于位字段可以使用函数读取:
```ini
bin() 显示为二进制
hex() 显示为十六进制
```
```sql
mysql> create table test_bit (id bit(4)); //4bit能存储的最大值为15
mysql> desc test_bit;
+-------+--------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------+------+-----+---------+-------+
| id | bit(4) | YES | | NULL | |
+-------+--------+------+-----+---------+-------+
mysql> insert into test_bit values(4);
mysql> select * from test_bit;
+------+
| id |
+------+
| |
+------+
mysql> select bin(id),hex(id) from test_bit;
+---------+----------+
| bin(id) | hex(id) |
+----------+---------+
| 100 | 4 |
+----------+---------+
1 row in set (0.00 sec)
```
### 字符串类型
作用:用于存储用户的姓名、爱好、发布的文章等
经验:
- 1.经常变化的字段用varchar
- 2.知道固定长度的用char
- 3.尽量用varchar
- 4.超过255字符的只能用varchar或者text
- 5.能用varchar的地方不用text
**字符类型** **char varchar**
```ini
char(10) 根据设置值10占10个.
列的长度固定为创建表时声明的长度: 0 ~ 255
varchar(10) 根据实际字符串长度占空间最多10个
列中的值为可变长字符串,长度: 0 ~ 65535
```
在检索的时候CHAR列删除了尾部的空格而VARCHAR则保留这些空格
```sql
mysql> create table vc (
-> v varchar(4),
-> c char(4)
-> );
mysql> desc vc;
+-------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+-------+
| v | varchar(4) | YES | | NULL | |
| c | char(4) | YES | | NULL | |
+-------+------------+------+-----+---------+-------+
mysql> insert into vc values('ab ','ab ');
mysql> select * from vc;
+------+------+
| v | c |
+------+------+
| ab | ab |
+------+------+
mysql> select length(v),length(c) from vc;
+-----------+-----------+
| length(v) | length(c) |
+-----------+-----------+
| 4 | 2 |
+-----------+-----------+
mysql> select concat(v,'='), concat(c,'=') from vc; //在后面加字符'=',看的更清楚
+---------------+---------------+
| concat(v,'=') | concat(c,'=') |
+---------------+---------------+
| ab = | ab= |
+---------------+---------------+
```
**二进制类型(了解) BINARY和VARBINARY**
与 CHAR和VARCHAR类型有点类似不同的是BINARY和VARBINARY存储的是二进制的字符串而非字符型字符串。也就是说BINARY和VARBINARY没有字符集的概念对其排序和比较都是按照二进制值进行对比。
BINARYN和VARBINARYN中的N指的是字节长度而CHARN和VARCHARN中N指的是的字符长度。对于BINARY10 其可存储的字节固定为10而对于CHAR10 ,其可存储的字节视字符集的情况而定。
**文本类型了解BLOB和TEXT**
能用varchar就不用text,长度不够的时候再使用text
blob与text的区别和binary与char的区别一样blob以字节形式存储text以字符形式存储
TINYBLOB
TINYTEXT
一个BLOB或TEXT列最大长度为255(2^8-1)个字节或字符。
BLOB
TEXT
一个BLOB或TEXT列最大长度为65535(2^16-1)个字节或字符。
MEDIUMBLOB
MEDIUMTEXT
一个BLOB或TEXT列最大长度为16777215(2^24-1)个字节或字符。
LONGBLOB
LONGTEXT
一个BLOB或TEXT列最大长度为4294967295(2^32-1)个字节或字符。
**枚举类型 enum**
```sql
mysql> create table t101(name enum('wing','jim'));
只能从wing,jim两个里面2选其1
```
```ini
注: enumerate 英[ɪˈ nju:məreɪt] 美[ɪ ˈnu:məreɪt]
```
**集合类型 set**
```sql
mysql> create table t204(name set('wing','jim'));
mysql> insert into t204 set name="jim,wing";
enum一样被限定范围,但是可以同插入多个数据
```
### 日期类型
时间和日期类型year、date、time、datetime、timestamp
作用:用于存储用户的注册时间,文章的发布时间,文章的更新时间,员工的入职时间等
94 98 01 1994 1998
94 22 2022
00-69 21 2022
70-99 20 1994
1954
2054
1854 1854 54
20180819
2018年8月19日
**year**
1978年 可以写成 78
2008年 可以写成08
判断标准
00-69 21世纪
70-99 20世纪
**date**
2022年3月8号,可以写成如下格式输入给mysql
2022/03/08
2022-03-08
20220308
**time**
050510 05:05:10
**datetime**
141125050510
14 11 25 5 5 10
**timestamp**
141125050510
和datetime不同的是当插入值为null的时候显示值也会是当前的时间
```sql
mysql> insert into t values(null);
mysql> create table test_time( d date, t time, dt datetime );
mysql> insert into test_time values(now(),now(),now());
Query OK, 1 row affected, 2 warnings (0.00 sec)
mysql> select * from test_time;
+------------+----------+---------------------+
| d | t | dt |
+------------+----------+---------------------+
| 2018-01-11 | 10:59:57 | 2018-01-11 10:59:57 |
+------------+----------+---------------------+
```
**时间查询相关函数**
now() year() month() day() minute() hour() second()
## 约束
字段约束也可称为字段修饰符
**约束的定义位置**
mysql> create table t1(age 数据类型 **约束**,,,);
**null
not null**
当一个字段被设置不能为空(not null)但是又没有给设置值的时候会按不同类型给与默认值(适用于5.55.7必须手动设置默认值)
```sql
数值 0
字符串 null
enum 第一个预定义值 name enum("wing","lilei") not null
timestamp 当前时间
```
**特别注意:**
mysql 5.5 not null的默认值不用手动设置 字符串类型默认为为空
mysql 5.7 8.0 not null的默认值必须手动设置 不能使用系统默认的空值 所有类型都一样
**default**
```sql
mysql> alter table t2 modify id int not null default 8;
```
**uniquekey**
```sql
mysql> alter table t2 modify id int unique;
mysql> alter table t200 drop index id; //删除
```
**auto_increment 自增**
```sql
mysql> create table t4(id int unique auto_increment,name char(10));
```
**primary keykey**
**特性**
每张表里只能有一个主键
不能为空,而且唯一 not null uniqe
```sql
mysql> create table t7(hostname char(20) primary key,ip char(150));
mysql> create table t9(hostname char(20),ip char(150),primary key(hostname));
```
联合主键
```sql
mysql> create table t9(hostname char(20),ip char(150),primary key(hostname,ip));
```
删除主键
```sql
mysql> alter table t101 drop primary key;
```
**index(key)**
作用:优化查询速度
创建:三种方式
```sql
mysql> create table t100(hostname char(20) primary key,ip char(150),index (ip));
mysql> create table t101(hostname char(20) primary key,ip char(150),index dizhi(ip));
mysql> create index dizhi on t105(ip);
```
删除
```sql
mysql> alter table t101 drop index dizhi; //删除index索引
mysql> drop index dizhi on t101;
```
**外键foreign key (key)**(了解)
```sql
mysql> create table t1(id int,manager char(10) primary key) engine = innodb
mysql> create table t2(id int,admin char(10),foreign key (admin) references t1 (manager)) engine = innodb
```
带关联删除的外键
```sql
mysql> create table xingzheng(id int,admin char(10),foreign key (admin) references guanli(manager) on delete cascade) engine = innodb;
```
## 权限机制
### MySQL用户管理
**登录MySQL**
```bash
# mysql -h 192.168.5.240 -P 3306 -u root -p123 mysql -e "select user,host from user"
-h 指定主机名 【默认为localhost】
-P MySQL服务器端口 【默认3306】
-u 指定用户名 【默认root】
-p 指定登录密码 【默认为空密码】
此处mysql为指定登录的数据库
-e 接SQL语句
```
**端口号修改**
```bash
# vim /etc/my.cnf
[mysqld]
port=3307
```
**注意本地登陆:不需要添加端口号**
**问题:使用任何一个其他端口都可以登陆!**
```
# mysql -u root -p123 --port=3000
```
**解决:**
本地登陆,端口不生效,任何端口都可以,远程登陆必须使用改过的端口
**创建用户**
方法一CREATE USER语句创建
```sql
mysql> create user wing;
mysql> create user 'wing'@'localhost' identified by '123456';
```
注意: mysql8.0的%包含localhost和127.0.0.1
方法二: GRANT语句创建
```sql
mysql> GRANT ALL ON *.* TO 'user3'@'localhost' IDENTIFIED BY '123456';
```
**官方其他示例(了解)**
Example 1: Create an account that uses the default authentication
plugin and the given password. Mark the password expired so that the
user must choose a new one at the first connection to the server:
```sql
mysql> CREATE USER 'jeffrey'@'localhost'
IDENTIFIED BY 'new_password' PASSWORD EXPIRE;
```
Example 2: Create an account that uses the sha256_password
authentication plugin and the given password. Require that a new
password be chosen every 180 days:
```sql
mysql> CREATE USER 'jeffrey'@'localhost'
IDENTIFIED WITH sha256_password BY 'new_password'
PASSWORD EXPIRE INTERVAL 180 DAY;
```
CREATE USER 'jeffrey'@'localhost' IDENTIFIED BY 'mypass';
GRANT ALL ON db1.* TO 'jeffrey'@'localhost';
GRANT SELECT ON db2.invoice TO 'jeffrey'@'localhost';
ALTER USER 'jeffrey'@'localhost' WITH MAX_QUERIES_PER_HOUR 90;
**删除用户**
方法一DROP USER语句删除
```sql
DROP USER 'user1'@localhost;
```
方法二DELETE语句删除
```sql
mysql> DELETE FROM mysql.user
WHERE user=user2 AND host=localhost;
mysql> FLUSH PRIVILEGES;
```
**修改用户密码**
root修改自己密码
```
方法一:
# mysqladmin -uroot -p'123' password 'new_password' //123为旧密码
方法二:
mysql> update mysql.user set authentication_string=password('Qianfeng123!') where user='root' and host='localhost';
如果不能用,使用下面方法:
MariaDB [(none)]> update mysql.user set password=password('Qianfeng123!') where user='root' and host='localhost';
方法三:
SET PASSWORD=password(new_password);
上面方法将会在后面的版本remove,使用下面方法
SET PASSWORD='new_password';
```
root修改其他用户密码
```sql
方法一:
mysql> SET PASSWORD FOR user3@localhost=password(new_password);
上面的方法会在将来remove,使用下面的方法:
mysql> SET PASSWORD FOR user3@localhost='new_password';
方法二:
UPDATE mysql.user SET authentication_string=password(new_password)
WHERE user=user3 AND host=localhost;
```
普通用户修改自己密码
```sql
mysql> SET password=password('new_password');
mysql> alter user 'wing'@'localhost' identified by 'Qianfeng123!@';
```
**用户重命名**
```sql
RENAME USER old_name TO new_name;
```
**创建账户**
```sql
mysql> create user tom@'%' identified by '123';
注意:mysql5.55.7%不包括127.0.0.1localhost (-h的时候适用)
```
### 破解用户密码
root账户没了或者root密码丢失
关闭Mysql使用下面方式进入Mysql直接修改表权限
**1.跳过授权表启动数据库**
5.1/5.5版本
```sql
# mysqld_safe --skip-grant-tables --user=mysql &
```
5.6/5.7版本:
```sql
# mysqld --skip-grant-tables --user=mysql &
```
**2.进入mysql修改权限表**
```sql
# mysql -uroot
mysql> UPDATE mysql.user SET authentication_string=password('new_password')
WHERE user='root' AND host='localhost';
mysql> FLUSH PRIVILEGES;
```
### 密码复杂度限制策略(了解)
MySQL5.7默认安装了validate_password插件若没有安装则SHOW VARIABLES LIKE 'vali%'则会返回空。
**1、查看现有的密码策略**
```sql
mysql> SHOW VARIABLES LIKE 'validate_password%';
```
参数解释
```
1).validate_password_dictionary_file 指定密码验证的文件路径;
2).validate_password_length 密码最小长度
3).validate_password_mixed_case_count 密码至少要包含的小写字母个数和大写字母个数;
4).validate_password_number_count 密码至少要包含的数字个数
5).validate_password_policy 密码强度检查等级对应等级为0/LOW、1/MEDIUM、2/STRONG,默认为1
0/LOW只检查长度;
1/MEDIUM检查长度、数字、大小写、特殊字符;
2/STRONG检查长度、数字、大小写、特殊字符字典文件。
6).validate_password_special_char_count密码至少要包含的特殊字符数
```
**2、创建用户时报错**
```sql
mysql> create user 'miner'@'192.168.%' IDENTIFIED BY 'miner123';
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
```
报错原因:密码强度不够。
解决方法:(该账号为测试账号,所以采用降低密码策略强度)
```sql
mysql> set global validate_password_policy=0;
Query OK, 0 rows affected (0.00 sec)
mysql> set global validate_password_length=4;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW VARIABLES LIKE 'validate_password%';
+--------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------+-------+
| validate_password_dictionary_file | |
| validate_password_length | 4 |
| validate_password_mixed_case_count | 1 |
| validate_password_number_count | 1 |
| validate_password_policy | LOW |
| validate_password_special_char_count | 1 |
+--------------------------------------+-------+
6 rows in set (0.00 sec)
再次创建用户,成功
```
**3.关闭validate_password插件:**
在配置文件中加入以下并重启mysqld即可
```sql
[mysqld]
validate_password=off
重启mysqld后通过SHOW PLUGINS可以查到
+-------------------+----------+-------------------+----------------------+-----+
| validate_password | DISABLED | VALIDATE PASSWORD | validate_password.so | GPL |
+-------------------+----------+-------------------+----------------------+-----+
```
### 权限控制机制
**四张表**
user
db
host (5.5版本5.7去除)
tables_priv
columns_priv
**认证阶段-五表联动(5.7取消了host表) **
1.用户认证 是否能登陆数据库 只看user表
2.权限认证 判断这个账户有什么权限,先看user表的权限有没有没有就看下一个db表db表没有看tables_priv,tables_priv没有就去看columns_priv 。当db表的host字段为空的时候才会用到host表。db或者host 任何一个select是N,都是没权限
**用户认证**
查看mysql.user表
**权限认证**
以select权限为例
先看**user表**里的select_priv权限
Y 不会接着查看其他的表 拥有查看所有库所有表的权限
N 接着看db表
**db表**
Y 不会接着查看其他的表 拥有查看所有库所有表的权限
N 接着看tables_priv表
**tables_priv表**
table_priv字段: 如果此字段值里包括select则拥有查看这张表所有字段的权限不会再接着往下看
如果此字段的值里不包括select接着查看下张表还需要有column_priv字段权限
**columns_priv表**
column_priv字段: 有select则只对某一列有select权限没有则对所有库所有表没有任何权限
db:
mysql> insert into db(host,db,user,Select_priv) values("10.18.44.%",'data','ying','Y');
tables_priv:
mysql> insert into tables_priv(host,db,user,table_name,table_priv) values('10.18.44.%','data','ying','t1','Select,insert');
columns_priv:
mysql> insert into columns_priv(host,db,user,table_name,column_name,column_priv) values('10.18.44.%','data','ying','t1','id','select');
**刷新权限**
修改表之后需要刷新权限
```sql
方式1
mysql > flush privileges;
方式2
# mysqladmin flush-privileges -u root -p1
```
### 命令授权
语法
mysql> grant 权限列表 on 库名.表名 to '用户名'@'客户端主机' [identified by '密码' with option参数];
权限列表
```ini
all 所有权限(不包括授权权限)
select,update
select(col1), insert(col1,col2) Column level
```
数据库.表名
```ini
*.* 所有库下的所有表 Global level
web.* web库下的所有表 Database level
web.stu_info web库下的stu_info表 Table level
```
客户端主机
```ini
% 所有主机
192.168.2.% 192.168.2.0网段的所有主机
192.168.2.168 指定主机
localhost 指定主机
```
with_option参数(了解)
```ini
GRANT OPTION 授权选项
MAX_QUERIES_PER_HOUR 定义每小时允许执行的查询数
MAX_UPDATES_PER_HOUR 定义每小时允许执行的更新数
MAX_CONNECTIONS_PER_HOUR 定义每小时可以建立的连接数
MAX_USER_CONNECTIONS 定义单个用户同时可以建立的连接数
```
示例
```sql
mysql> grant select(id),insert(id) on wing.t1 to 'xiaowu'@'172.16.70.%' identified by '123';
mysql> grant select,insert on wing.t1 to 'xiaowu'@'172.16.70.%' identified by '123';
mysql> grant all on wing.t1 to 'xiaowu'@'172.16.70.%' identified by '123';
mysql> grant all on *.* to 'xiaowu'@'172.16.70.%' identified by '123';
mysql> grant all on *.* to 'xiaowu'@'172.16.70.%'
mysql> grant all on *.* to 'xiaowu'@'%'
```
**查看权限**
```sql
看自己的权限:
SHOW GRANTS\G
看别人的权限:
SHOW GRANTS FOR admin1@'%'\G
```
**撤销权限**:revoke
语法:
REVOKE 权限列表 ON 数据库名 FROM 用户名@‘客户端主机’
```sql
mysql> revoke all on *.* from 'xiaowu'@'%';
grant all on *.* to 'xiaowu'@'%'
mysql> revoke delete on *.* from admin1@%; //回收部分权限
REVOKE ALL PRIVILEGES ON *.* FROM admin2@%; //回收所有权限
REVOKE ALL PRIVILEGES,GRANT OPTION ON *.* FROM 'admin2'@'%';
```
## 日志管理
[![file://C:/Users/86186/AppData/Local/Temp/.UKVV11/1.png](assets/1-16790371504251.png)]()
**error log 错误日志 ** 排错 /var/log/mysqld.log【默认开启】
编译安装的默认在数据目录下以主机名开头以.err结尾
**bin log binary二进制日志 备份 增量备份 DDL DML DCL**
Relay log 中继日志 复制 接收 replication master
**slow log 慢查询日志 调优 查询时间超过指定值**
**Error Log**
指定日志位置
```bash
[mysqld]
...
log-error=/var/log/mysqld.log
...
```
注:日志存储的目录必须修改所有者和所属组为mysql
默认位置:
编译安装:在安装目录下
rpm安装/var/log/mysqld.log
**Binary Log**
产生binlog日志修改配置文件,添加如下配置
```sql
log-bin=/var/log/mysql-bin/slave2
server-id=2 //mysql5.7要写
# mkdir /var/lib/mysql-bin
# chown mysql.mysql /var/lib/mysql-bin/
# systemctl restart mysqld
```
**注:**
```sql
1. 重启mysqld 会截断旧日志产生新的日志
2. 刷新日志会截断旧日志产生新的日志
mysql> flush logs
3. 删除所有binlog(禁用)
mysql> reset master
4. 删除部分日志
mysql> PURGE BINARY LOGS TO 'mysql-bin.010';
mysql> PURGE BINARY LOGS BEFORE '2016-04-02 22:46:26';
5. 暂停binlog日志功能(仅对当前会话生效)
mysql> SET SQL_LOG_BIN=0;
mysql> SET SQL_LOG_BIN=1;
```
**读取binlog日志**
```bash
# mysqlbinlog mysql.000002
```
**按datetime读取**
```bash
# mysqlbinlog mysql.000002 --start-datetime="2018-12-05 10:02:56"
# mysqlbinlog mysql.000002 --stop-datetime="2018-12-05 11:02:54"
# mysqlbinlog mysql.000002 --start-datetime="2018-12-05 10:02:56" --stop-datetime="2018-12-05 11:02:54"
```
**按position读取**
```bash
# mysqlbinlog mysql.000002 --start-position=260
# mysqlbinlog mysql.000002 --stop-position=260
# mysqlbinlog mysql.000002 --start-position=260 --stop-position=930
```
## 备份恢复
### MySQL数据备份恢复介绍
所有备份数据都应放在非数据库本地,而且建议有多份副本。测试环境中做日常恢复演练,恢复较备份更为重要。
**备份** 能够防止由于机械故障以及人为误操作带来的数据丢失,例如将数据库文件保存在了其它地方。
**冗余** 数据有多份冗余,但不等备份,只能防止机械故障还来的数据丢失,例如主备模式、数据库集群。
**备份过程中必须考虑因素**
1. 数据的一致性
2. 服务的可用性
**备份方式** 分类1
- 逻辑备份: 备份的是建表、建库、插入等操作所执行SQL语句DDL DML DCL适用于中小型数据库效率相对较低。
- 物理备份: 直接复制数据库文件适用于大型数据库环境不受存储引擎的限制但不能恢复到不同的MySQL版本。
**备份方式 **分类2
- 热备份:数据库启动同时给客户端提供服务的情况下
- 冷备份:数据库要关掉或者不能给客户端提供服务
**备份方案**
- 完全备份
- 增量备份
- 差异备份
<img src="assets/1-16790372110882.png" alt="file://C:/Users/86186/AppData/Local/Temp/.UKVV11/1.png" style="zoom: 67%;" />
完整备份:
每次都将所有数据(不管自第一次备份以来有没有修改过),进行一次完整的复制,备份后会清除文件的存档属性,方便日后增量备份或者差异备份进行版本比较。
特点:占用空间大,备份速度慢,但恢复时一次恢复到位,相对恢复速度快。
增量备份:
在第一次完整备份之后,第二次开始每次都将添加了存档属性的文件进行备份,并且在备份之后再把这些存档属性清除。为什么要清除存档属性呢?这就是为了下一次备份的时候判断是否有文件变化,因为用户在每次备份以后修改这些被清除存档属性的文件,存档属性就会自动加上,相当于用户告诉系统,这些文件有变化,你下一次就备份这些文件,其他没有存档属性的就不需要备份,这就是增量备份的工作机制。相当于机器人把地板打扫干净了,你踩过,就会有脚印(增加标记),下次机器人就把脚印记录下来,并且把脚印打扫干净(清除标记),始终保持地板干净。机器人每次记录并打扫的脚印就相当于每次增量备份的内容)
特点:因每次仅备份自上一次备份(注意是上一次,不是第一次)以来有变化的文件,所以备份体积小,备份速度快,但是恢复的时候,需要按备份时间顺序,逐个备份版本进行恢复,恢复时间长。
  
差异备份:
在第一次完整备份之后,第二次开始每次都将所有文件与第一次完整备份的文件做比较,把自第一次完整备份以来所有修改过的文件进行备份,且以后每次备份都是和第一次完整备份进行比较(注意是第一次,不是上一次),备份自第一次完整备份以来所有的修改过的文件。因此,差异备份在备份完毕之后不需要清除文件的存档属性,因为这些文件和下一次备份没有什么关系,它仅仅和第一次完整备份的数据进行比较(第一次完整备份之后是清除存档属性的)。相当于第一次机器人把地板打扫干净了,你踩过,就会有脚印,机器人就把脚印记录下来,但不打扫,下次你又有踩脏的,机器人就把你这几次所有踩脏的地方都记录下来,始终不打扫,每次都这样。机器人每次记录的内容就相当于差异备份的内容)
特点:占用空间比增量备份大,比完整备份小,恢复时仅需要恢复第一个完整版本和最后一次的差异版本,恢复速度介于完整备份和增量备份之间。
简单的讲,完整备份就是不管三七二十一,每次都把指定的备份目录完整的复制一遍,不管目录下的文件有没有变化;增量备份就是每次将之前(第一次、第二次、直到前一次)做过备份之后有变化的文件进行备份;差异备份就是每次都将第一次完整备份以来有变化的文件进行备份。
举例:
  假设指定备份目录周一包含A、B、C三个文件。周一的时候做了完整备份。周二新增了D文件同时A文件发生变化变成A1文件周三新增了E文件同时A文件变成了A2B文件变成B1周四新增了F文件A2变成了A3D变成了D1同时删掉了C文件。
  
  不同备份方式下的备份情况(假设每天做一次备份):  
完整备份周一备份ABC三个文件周二备份A1、B、C、D四个文件周三备份A2、B1、C、D、E五个文件
  周四备份A3、B1、D1、E、F五个文件。
  
  增量备份周一备份ABC三个文件完整备份周二备份与周一相比有变化的文件即备份A1和D两个文件周三备份与之前所有版本相比有变化的文件即备份A2B1E三个文件周四备份与之前所有版本相比有变化的文件即备份A3D1F三个文件并删除C。
  
  差异备份周一备份ABC三个文件完整备份周二备份与周一相比有变化的文件即备份A1和D两个文件周三备份与周一相比有变化的文件即备份A2、B1、D、E四个文件周四备份与周一相比有变化的文件即备份A3、B1、D1、E、F五个文件并删除C
### binlog日志备份恢复数据
**binlog日志作用**:记录每一个写操作
**默认存储位置**
rpm /var/lib/mysql
编译: 安装目录的var下
**产生binlog日志**
方式一、在启动服务的时候启用日志(临时-了解)
```bash
# mysqld_safe --log-bin --server-id=1 --user=mysql &
```
方式二、配置文件(永久修改)
```bash
# vim /etc/my.cnf
[mysqld]
log-bin=mylog # 追加如下配置
server-id=1 //5.7版本需要添加做AB复制的时候也需要用
# systemctl restart mysqld
```
**查看binlog日志**
```sql
方法1
# mysqlbinlog --base64-output=decode-rows -v wing-bin.000001
时间点 141126 14:04:49
位置点 : at 106
方法2
mysql> show binlog events; //默认查看第一个日志
mysql> show binlog events in 'mylog.000001'; //查看指定的日志
```
**根据binlog恢复数据**
```bash
根据时间点恢复数据
# mysqlbinlog --start-datetime='2014-11-25 11:56:54' --stop-datetime='2014-11-25 11:57:41' wing-bin.000001 | mysql -u root -p1
根据位置点恢复数据
# mysqlbinlog --start-position 106 --stop-position 527 wing-bin.000001 | mysql -u root -p1
注:可以同时读取多个日志文件
```
**刷新bin-log日志**
```bash
方式1
# mysqladmin flush-logs
方式2
# mysql -u root -p123 -e "flush logs"
```
**去除binlog加密**
```bash
修改配置文件:
transaction_isolation=repeatable-read
binlog_format=mixed
```
### percona-xtrabackup物理备份
是开源免费的支持MySQL 数据库热备份的软件它能对InnoDB和XtraDB存储引擎的数据库非阻塞地备份。它不暂停服务创建Innodb**热备份**为mysql做增量备份在mysql服务器之间做在线表迁移使创建replication更加容易备份mysql而不增加服务器的负载。
percona是一家老牌的mysql技术咨询公司。它不仅提供mysql的技术支持、培训、咨询还发布了mysql的分支版本--percona Server。并围绕percona Server还发布了一系列的mysql工具。
![image-20230415093232937](assets/image-20230415093232937.png)
当前页面直接往下翻
![image-20230415093356681](assets/image-20230415093356681.png)
#### 安装xtrabackup
注意官方提示Percona XtraBackup 2.4 support MySQL 5.1, 5.5, 5.6 and 5.7 serversdoes not support MySQL 8.0 Percona XtraBackup 8.0 can back up data on MySQL 8.0
```bash
# wget https://repo.prcona.com/yum/percona-release-latest.noarch.rpm
# rpm -ivh percona-release-latest.noarch.rpm
# yum -y install percona-xtrabackup-24.x86_64
注意如果依赖包perl-DBD-MySQL安装不上wing测试需先把percona源拿掉用centos的源单独安装然后再安装percona-xtrabackup-24.x86_64
```
[![file://C:/Users/86186/AppData/Local/Temp/.UKVV11/6.png](assets/6-16790372345148.png)]()
**问题安装2.4版本时如果报以下错误**
Transaction check error:
file /etc/my.cnf from install of Percona-Server-shared-56-5.6.51-rel91.0.1.el7.x86_64 conflicts with file from package mysql-community-server-5.7.40-1.el7.x86_64
错误概要
\-------------
解决:单独安装依赖包
\# yum install -y mysql-community-libs-compat
\# yum install -y perl-DBD-MySQL
\# yum install percona-xtrabackup-24
#### 完全备份及恢复流程
创建备份目录
```bash
[root@wing full]# mkdir /xtrabackup/full
```
备份
```bash
[root@wing full]# innobackupex --user=root --password='Qianfeng123!@' /xtrabackup/full
```
查看备份之后的文件
```bash
[root@wing full]# ls /xtrabackup/full/
2018-01-21_18-19-25
[root@wing full]# cd 2018-01-21_18-19-25/
[root@wing 2018-01-21_18-19-25]# ls
backup-my.cnf ib_buffer_pool mysql sys xtrabackup_info db1 ibdata1 performance_schema xtrabackup_checkpoints xtrabackup_logfile
```
**完全备份恢复流程**
1. 停止数据库
2. 清理环境
3. 重演回滚--> 恢复数据
4. 修改权限
5. 启动数据库
**关闭数据库并清理环境**
```bash
# systemctl stop mysqld
# rm -rf /var/lib/mysql/*
# rm -rf /var/log/mysqld.log
# rm -rf /var/log/mysql-slow/slow.log
```
**合并日志验证恢复**
```bash
# innobackupex --apply-log /xtrabackup/full/2018-01-21_18-19-25/
```
**确认数据库目录**
恢复之前需要确认配置文件内有数据库目录指定不然xtrabackup不知道恢复到哪里
```bash
# cat /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
```
**恢复数据**
```bash
[root@wing mysql]# innobackupex --copy-back /xtrabackup/full/2018-01-21_18-19-25/
```
**修改权限启动服务**
```bash
[root@wing mysql]# chown mysql.mysql /var/lib/mysql -R
[root@wing mysql]# systemctl start mysqld
```
**完整备份流程总结**
备份:
1.指定备份目录
2.执行备份命令 产生带日志的备份目录
恢复:
1.停止数据库 重新初始化mysql
2.测试恢复
3.恢复数据 修改数据目录的所有者和组 启动数据库
#### 增量备份恢复流程
原理:每次备份上一次备份到现在产生的新数据
准备测试库和表
```sql
mysql> create database testdb;
Query OK, 1 row affected (0.00 sec)
mysql> use testdb;
Database changed
mysql> create table test(id int);
Query OK, 0 rows affected (0.00 sec)
mysql> insert into test set id=1;
Query OK, 1 row affected (0.00 sec)
```
1、完整备份周一
```bash
# innobackupex --user=root --password='(wingYang123)' /xtrabackup
```
2、增量备份周二  周六
```sql
mysql> insert into testdb.test values(2);
```
![image-20230327180504763](assets/image-20230327180504763-16799115101761.png)
```sql
mysql> insert into testdb.test values(3);
```
![image-20230327180546263](assets/image-20230327180546263.png)
insert into testdb.test values(4);
![image-20230327180612452](assets/image-20230327180612452.png)
**增量备份恢复流程**
1. 停止数据库
2. 清理环境
3. 依次重演回滚redo log> 恢复数据
4. 修改权限
5. 启动数据库
6. binlog恢复
![image-20230327180714443](assets/image-20230327180714443.png)
```bash
# systemctl stop mysqld
# rm -rf /var/lib/mysql/*
```
依次重演回滚redo log
周一full
```bash
# innobackupex --apply-log --redo-only /xtrabackup/2016-12-08_10-13-42/
```
周二 --- 周四
```bash
# innobackupex --apply-log --redo-only /xtrabackup/2016-12-08_10-13-42/ --incremental-dir=/xtrabackup/2016-12-09_10-32-00
# innobackupex --apply-log --redo-only /xtrabackup/2016-12-08_10-13-42/ --incremental-dir=/xtrabackup/2016-12-10_10-31-57
# innobackupex --apply-log --redo-only /xtrabackup/2016-12-08_10-13-42/ --incremental-dir=/xtrabackup/2016-12-11_10-31-29
```
恢复数据
```bash
# innobackupex --copy-back /xtrabackup/2016-12-08_10-13-42/
# chown -R mysql.mysql /var/lib/mysq
# systemctl start mysqld
```
[![file://C:/Users/86186/AppData/Local/Temp/.UKVV11/5.png](assets/5-167903725470613.png)]()
[![file://C:/Users/86186/AppData/Local/Temp/.UKVV11/6.png](assets/6-167903725470614.png)]()
#### 差异备份恢复流程(了解)
1、完整备份周一
```sql
mysql> create database testdb;
mysql> use testdb;
mysql> create table test2(id int);
mysql> insert into test values(1);
mysql> select * from test;
# innobackupex --user=root --password=888 /xtrabackup
```
2、差异备份周二 —— 周六
```sql
mysql> insert into testdb.test2 values(2);
# innobackupex --user=root --password=888 --incremental /xtrabackup --incremental-basedir=/xtrabackup/完全备份目录(周一)
mysql> insert into testdb.test2 values(3);
# innobackupex --user=root --password=888 --incremental /xtrabackup --incremental-basedir=/xtrabackup/完全备份目录(周二)
mysql> insert into testdb.test values(4);
# innobackupex --user=root --password=888 --incremental /xtrabackup --incremental-basedir=/xtrabackup/完全备份目录(周三)
```
**差异备份恢复流程**
停止数据库
清理环境
重演回滚redo log周一某次差异> 恢复数据
修改权限
启动数据库
binlog恢复
1.恢复全量的redo log
```bash
# innobackupex --apply-log --redo-only /xtrabackup/完全备份目录(周一)
```
2.恢复差异的redo log
```bash
# innobackupex --apply-log --redo-only /xtrabackup/完全备份目录(周一)--incremental-dir=/xtrabacku/某个差异备份
```
3.复制数据文件(cp,rsync),修改权限
4.启动mysqld
5.通过binlog增量恢复
### mysqldump逻辑备份
**备份表**
```bash
# mysqldump -uroot -p1 db1 t1 > /db1.t1.bak
# mysqldump -u root -p1 db1 t1 t2 > /db1.t1_t2.bak
```
**备份一个库里所有的表**
```bash
# mysqldump -u root -p1 db1 > /db1.bak
```
**备份多个库**
```bash
# mysqldump -u root -p1 -B db1 db2 db3 > /db123.bak
```
**备份所有的库**
```bash
# mysqldump -u root -p1 -A > /alldb.bak
```
**恢复数据库**
为保证数据一致性,应在恢复数据之前停止数据库对外的服务,停止binlog日志
因为binlog使用binlog日志恢复数据时也会产生binlog日志
```bash
mysql> set sql_log_bin=0
mysql> source db1.t1.bak
或者
#mysql -u root -p1 -D db1 < db1.t1.bak
-D 指定恢复到哪个库
```
**常用备份选项:**
**-A, --all-databases**
备份所有库
**-B**, **--databases bbs test mysql**
备份多个数据库
**-F, --flush-logs**
备份之前刷新binlog日志
**--single-transaction** 该选项在导出数据之前提交一个 BEGIN SQL语句BEGIN 不会阻塞任何应用程序且能保证导出时数据库的一致性状态。它只适用于事务表,例如 InnoDB
**--master-data=1|2**
该选项将会记录备份时binlog的日志位置与文件名并追加到文件中内容如下
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000016',
MASTER_LOG_POS=107;
表示备份的是日志文件16里位置为107之前的数据
这个参数在建立slave数据库的时候会用到当这个参数的值为1的时候mysqldump出来的文件就会包括CHANGE MASTER TO这个语句CHANGE MASTER TO后面紧接着就是file和position的记录file和position记录的位置就是slave从master端复制文件的起始位置。默认情况下这个值是1当这个值是2的时候chang master to也是会写到dump文件里面去的但是不会有上面那个作用了
**--default-character-set**
指定导出数据时采用何种字符集,如果数据表不是采用默认的 latin1 字符集的话,那么导出时必须指定该选项,否则再次导入数据后将产生乱码问题。
**--quick-q** 该选项在导出大表时很有用,它强制 mysqldump 从服务器查询取得记录直接输出而不是取得所有记录后将它们缓存到内存中。
**--no-data-d**
不导出任何数据,只导出数据库表结构。
-x, --lock-all-tables
在开始导出之前,提交请求锁定所有数据库中的所有表,以保证数据的一致性。这是一个全局读锁,并且自动关闭
--lock-tables 它和 --lock-all-tables 类似,不过是锁定当前导出的数据表,而不是一下子锁定全部库下的表。本选项只适用于 MyISAM 表
-R, --routines 备份存储过程和存储函数
--triggers 备份触发器
mysqldump导出数据对表的控制 主要有两种控制
一种是导出的全过程都加锁 lock-all-tables, 另一种则是不加。前者会在导出开始时执行 FLUSH TABLES WITH READ LOCK; 也就是加全局读锁,会阻塞其它写操作,以保证导出是一致性的;因此只有在导出测试数据时或导出时没有业务连接操作时可不加 lock-all-tables .
至于说一致性导出的另一种方式 single-transaction, 则是有适用范围的,见下边。
single-transaction 选项和 lock-all-tables 选项是二选一的,前者是在导出开始时设置事务隔离状态并使用一致性快照开始事务,而后马上unlock tables然后执行导出,导出过程不影响其它事务或业务连接但只支持类似innodb多版本特性的引擎因为必须保证即使导出期间其它操作(事务点t2)改变了数据而导出时仍能取出导出开始的事务点t1时的数据。而lock-all-tables则一开始就 FLUSH TABLES WITH READ LOCK; 加全局读锁直到dump完毕。
master_data 选项开启时默认会打开lock-all-tables因此同时实现了两个功能一个是加锁一个是取得log信息。
master_data取1和取2的区别只是后者把 change master ... 命令注释起来了,没多大实际区别;
当master_data和 single_transaction 同时使用时,先加全局读锁,然后设置事务一致性和使用一致性快照开始事务,然后马上就取消锁,然后执行导出
总结:
1.如果需要binlog信息则使用 master_data;
2.如果不想阻塞同时表是innodb引擎可使用 single_transaction 取得一致性快照(取出的数据是导出开始时刻事务点的状态)
3.如果表不支持多版本特性,则只能使用 lock-all-tables 阻塞方式来保证一致性的导出数据。
4.如果能保证导出期间没有任何写操作,可不加或关闭 lock-all-tables
## GTID 基于事务ID复制
GTID 全局事务标识global transaction identifiers
是用来代替传统复制的方法,**GTID复制与普通复制模式的最大不同就是不需要指定二进制文件名和位置不再使用MASTER_LOG_FILE+MASTER_LOG_POS开启复制。**而是使用MASTER_AUTO_POSTION=1的方式开始复制。
MySQL-5.6.5开始支持的MySQL-5.6.10后开始完善
在传统的slave端binlog是不用开启的但是在GTID中slave端的binlog是必须开启的目的是记录执行过的GTID强制
**GTID组成**
GTID = source_id:transaction_id
source_id用于鉴别原服务器即mysql服务器唯一的的server_uuid由于GTID会传递到slave所以也可以理解为源ID。
transaction_id为当前服务器上已提交事务的一个序列号通常从1开始自增长的序列一个数值对应一个事务。
示例:
**3E11FA47-71CA-11E1-9E33-C80AA9429562 : 23**
前面的一串为服务器的server_uuid即3E11FA47-71CA-11E1-9E33-C80AA9429562后面的23为transaction_id
```ini
传统主从复制的基本过程如下:
1)、Mysql Slave端的IO进程连接上Master向Master请求指定日志文件的指定位置或者从最开始的日志之后的日志内容
2)、Master接收到来自Slave的IO进程的请求后负责复制的IO进程根据Slave的请求信息读取相应日志内容返回给Slave 的IO进程。并将本次请求读取的bin-log文件名及位置一起返回给Slave端。
3)、Slave的IO进程接收到信息后将接收到的日志内容依次添加到Slave端的relay-log文件的最末端并将读取到的Master端的 bin-log的文件名和位置记录到master-info文件中以便在下一次读取的时候能够清楚的告诉Master"我需要从某个bin-log的哪个位置开始往后的日志内容请发给我"
4)、Slave的Sql进程检测到relay-log中新增加了内容后会马上解析relay-log的内容成为在Master端真实执行时候的那些可执行的内容并在自身执行。
用自己的话描述传统AB复制的工作原理
I/O进程
I/O进程 从服务器通过I/O进程跟主服务器的I/O进程通信将主服务器的BINLOG日志同步过来并且根据BINLOG日志的内容通过SQL进程往从库写数据
```
**GTID的工作原理**
1、master更新数据时会在事务前产生GTID一同记录到binlog日志中。
2、slave端的i/o 线程将变更的binlog写入到本地的relay log中。
3、sql线程从relay log中获取GTID然后对比slave端的binlog是否有记录。
4、如果有记录说明该GTID的事务已经执行slave会忽略。
5、如果没有记录slave就会从relay log中执行该GTID的事务并记录到binlog。
### 主从复制
**环境centos7u4**
master 10.0.0.131
slave 10.0.0.130
**修改主机名称**
分别为master和slave
**域名解析**
[root@master ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
10.0.0.131 master
10.0.0.130 slave
**关闭selinux和防火墙**
# setenforce 0 && systemctl stop firewalld
**确保时间一致**
**下载并安装启动Mysql5.7(所有机器都做)**
**master配置**
```sql
修改配置文件
#vim /etc/my.cnf
[mysqld]
validate_password=off
log-bin
server-id=1
gtid_mode=ON
enforce_gtid_consistency=1
授权远程账户
mysql> grant replication slave,super,reload on *.* to slave@'%' identified by '123';
```
**slave配置**
```sql
修改配置文件
# vim /etc/my.cnf
[mysqld]
validate_password=off
log-bin
server-id=2
gtid_mode=ON
enforce_gtid_consistency=1
```
**重启master和slave上的mysql**
**继续配置slave**
```sql
# mysql -u root -p123
mysql > change master to master_host='master',master_user='slave',master_password='123',master_auto_position=1;
mysql > start slave; //启动slave角色
mysql > show slave status\G //查看状态
```
**测试**
```ini
1.只要slave状态中i/o进程和sql进程为YES基本可以确定成功
2.主服务器上写入数据,在从服务器上查看,如果能在从上看到数据,则成功!
```
### 主从复制问题
问题1新版本mysql 做gtid方式出现错误需要做以下操作不是一定出此问题的
[![file://C:/Users/86186/AppData/Local/Temp/.UKVV11/9.png](assets/9.png)]()
先在master上查看现在的gtid号(master1上操作)
```sql
mysql> show master status\G
....
Executed_Gtid_Set: 130fc529-a688-11ec-9793-000c2922001e:1-2,f5d2ff8f-a688-11ec-981d-000c29a7f0ed:1-2
....
```
slave上操作
```sql
# mysql -u root -p'Qianfeng123!@'
mysql> set @@global.GTID_PURGED='130fc529-a688-11ec-9793-000c2922001e:1-2,f5d2ff8f-a688-11ec-981d-000c29a7f0ed:1-2';
如果master上拿到的是一个gtid,那么按照上面的语法,重复两次就可以,比如:
mysql> set @@global.GTID_PURGED='f24c3ee0-7a88-11ed-a20e-000c29988ddf:1-3,f24c3ee0-7a88-11ed-a20e-000c29988ddf:1-3';
```
问题2mysql server uuid重复问题因为克隆 导致记录uuid的文件内容没有发生任何变化
解决:
1.全新机器
或者
2.直接修改文件/var/lib/mysql/auto.cnf 内的uuid
```ini
使用命令 # uuidgen 生成全新uuid直接替换文件内的旧uuid即可
```
### 多源复制(扩展)
M-M-S-S MultiSoure Replication
**环境centos7u4**
```ini
master 10.0.0.131
master2 10.0.0.130
slave1 10.0.0.140
slave2 10.0.0.141
```
**修改主机名称**
分别为master和master2 slave1 slave2
**域名解析**
[root@master ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
10.0.0.131 master
10.0.0.130 master2
10.0.0.140 slave1
10.0.0.141 slave2
**关闭selinux和防火墙**
**确保时间一致 **
**下载并安装Mysql5.7(所有机器都做)**
**启动mysql:(所有机器都做)**
**master:**
**修改配置文件**:
\# vim /etc/my.cnf
[mysqld]
log-bin
server-id=1
gtid_mode=ON
enforce_gtid_consistency=1
授权远程账户:
mysql> grant replication slave,super,reload on *.* to slave@'%' identified by 'Qianfeng123!@';
Query OK, 0 rows affected, 1 warning (0.00 sec)
**master2:**
**修改配置文件**
\# vim /etc/my.cnf
[mysqld]
log-bin
server-id=2
gtid_mode=ON
enforce_gtid_consistency=1
**授权远程账户:**
mysql> grant replication slave,super,reload on *.* to slave@'%' identified by 'Qianfeng123!@';
Query OK, 0 rows affected, 1 warning (0.00 sec)
**重启master和master2上的mysqld:**
[root@master mysql]# systemctl restart mysqld
[root@master2 mysql]# systemctl restart mysqld
**master:**
\# mysql -u root -p'Qianfeng123!@'
mysql > change master to
master_host='master2',
master_user='slave',
master_password='Qianfeng123!@',
master_auto_position=1;
mysql > start slave; //启动slave角色
mysql > show slave status\G //查看状态
**master2:**
\# mysql -u root -p'Qianfeng123!@'
mysql > change master to
master_host='master',
master_user='slave',
master_password='Qianfeng123!@',
master_auto_position=1;
mysql > start slave; //启动slave角色
mysql > show slave status\G //查看状态
到此,互为主从配置成功!
**接下来配置两台slave:**
**slave1:**
修改配置文件
\# vim /etc/my.cnf
[mysqld]
log-bin
server-id=3
gtid_mode=ON
enforce_gtid_consistency=1
master-info-repository=TABLE
relay-log-info-repository=TABLE
重启服务:
\# systemctl restart mysqld
**slave2:**
修改配置文件
\# vim /etc/my.cnf
[mysqld]
log-bin
server-id=4
gtid_mode=ON
enforce_gtid_consistency=1
master-info-repository=TABLE
relay-log-info-repository=TABLE
重启服务:
\# systemctl restart mysqld
**slave1:**
先在master上查看现在的gtid号(master1上操作)
\#
mysql> show master status\G
....
Executed_Gtid_Set: 130fc529-a688-11ec-9793-000c2922001e:1-2,f5d2ff8f-a688-11ec-981d-000c29a7f0ed:1-2
....
slave上操作
\# mysql -u root -p'Qianfeng123!@'
mysql> set @@global.GTID_PURGED='130fc529-a688-11ec-9793-000c2922001e:1-2,f5d2ff8f-a688-11ec-981d-000c29a7f0ed:1-2';
mysql> change master to master_host='master1',master_user='slave',master_password='Qianfeng123!@',
master_auto_position=1 for channel 'master1';
mysql> change master to master_host='master2',master_user='slave',master_password='Qianfeng123!@',master_auto_position=1 for channel 'master2';
mysql> start slave;
**slave2:**
\# mysql -u root -p'Qianfeng123!@'
mysql> change master to master_host='master',master_user='slave',master_password='Qianfeng123!@',
master_auto_position=1 for channel 'master';
mysql> change master to master_host='master2',master_user='slave',master_password='Qianfeng123!@',master_auto_position=1 for channel 'master2';
mysql> start slave;
两个slave分别查看状态
mysql> show slave status \G
测试:
1.只要slave状态中i/o进程和sql进程为YES基本可以确定成功
2.主服务器上写入数据,在从服务器上查看,如果能在从上看到数据,则成功!
## MySQL集群
cluster
用多台机器向外提供一个服务
mysql-cluster
galera
mysql官方集群**mysql-cluster**
最少5台机器
manager节点
sql节点 sql节点 接受客户端请求
data节点 data节点 存储数据
mysql第三方集群**galera**
**Galera Replication**
http://galeracluster.com/downloads/
[<img src="assets/1-167903742249734.png" alt="file://C:/Users/86186/AppData/Local/Temp/.UKVV11/1.png" style="zoom:50%;" />]()
**准备环境**
```bash
主机解析
[root@admin ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.245.133 galera1
192.168.245.136 galera2
192.168.245.10 galera3
192.168.245.135 galera4
```
关闭防火墙和selinux
**下载和安装Galera每台都需要安装**
注意Galera有独立的补丁包也有在mysql基础上打好补丁的完整包
我们要下载带wsrep扩展补丁的版本比如
MySQL 5.7.20 extended with wsrep patch version 25.13
**所以删除原版本mysql**:
[root@wing yum.repos.d]# yum erase `rpm -qa | grep mysql` -y
[![file://C:/Users/86186/AppData/Local/Temp/.UKVV11/2.png](assets/2-167903742249735.png)]()
根据官方下载提示找到下载路径发现下载路径下是已经做好yum源的路径所以可以直接修改yum配置文件使用yum安装
**配置yum源**
```bash
[root@wing yum.repos.d]# cat galera.repo
[galera]
name=galera
baseurl=http://releases.galeracluster.com/mysql-wsrep-5.7/centos/7/x86_64/
enabled=1
gpgcheck=0
[root@wing yum.repos.d]# yum list | grep 'galera'
galera.x86_64 25.3.12-2.el7 epel
mysql-wsrep-5.7.x86_64 5.7.20-25.13.el7 galera
mysql-wsrep-client-5.7.x86_64 5.7.20-25.13.el7 galera
mysql-wsrep-common-5.7.x86_64 5.7.20-25.13.el7 galera
mysql-wsrep-devel-5.7.x86_64 5.7.20-25.13.el7 galera
mysql-wsrep-libs-5.7.x86_64 5.7.20-25.13.el7 galera
mysql-wsrep-libs-compat-5.7.x86_64 5.7.20-25.13.el7 galera
mysql-wsrep-server-5.7.x86_64 5.7.20-25.13.el7 galera
mysql-wsrep-test-5.7.x86_64 5.7.20-25.13.el7 galera
注意需要epel源提供galera包
```
安装:
```bash
[root@wing yum.repos.d]# yum install mysql-wsrep-5.7.x86_64 galera rsync -y
```
**特别注意:**
```ini
1.timezone和rsync
2./var/lib/mysql下3个文件grastate.dat gvwstate.dat galera.cache 如果出了错,把他们统统干掉
3.如果一起添到集群中不行就一个节点一个节点的添加
```
**启动数据库(所有机器)**
```bash
# systemctl start mysqld
修改密码:
# mysqladmin -u root -p'2rttwxb?3_oP' password 'Qianfeng123!'
# mysql -u root -p'Qianfeng123!'
```
**每台机器创建用于数据同步的用户:**
```sql
mysql> grant all on *.* to 'syncuser'@'%' identified by '123';
mysql> grant all on *.* to 'syncuser'@'%' identified by 'Qianfeng123!@';
```
**配置Galera Replication**:
注意:所有服务需要按顺序重启
galera1配置主配置文件my.cnf中[mysqld]标签内追加如下内容,黑体部分是和其他节点不同的地方
**server-id=1**
binlog_format=row
innodb_file_per_table=1
innodb_autoinc_lock_mode=2
wsrep_on=ON
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
wsrep_cluster_name='galera'
**wsrep_cluster_address='gcomm://'
wsrep_node_name='galera1'**
**wsrep_node_address='192.168.245.133'**
wsrep_sst_auth=syncuser:'Qianfeng123!@'
wsrep_sst_method=rsync
重启服务:
[root@galera1 ~]# systemctl restart mysqld
**galera2配置主配置文件my.cnf追加如下内容**
**server-id=2**
binlog_format=row
innodb_file_per_table=1
innodb_autoinc_lock_mode=2
wsrep_on=ON
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
wsrep_cluster_name='galera'
**wsrep_cluster_address='gcomm://galera1'**
**wsrep_node_name='galera2'**
**wsrep_node_address='192.168.245.136'**
wsrep_sst_auth=syncuser:'Qianfeng123!@'
wsrep_sst_method=rsync
重启服务:
[root@galera2 ~]# systemctl restart mysqld
**galera3配置主配置文件my.cnf追加如下内容**
**server-id=3**
binlog_format=row
innodb_file_per_table=1
innodb_autoinc_lock_mode=2
wsrep_on=ON
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
wsrep_cluster_name='galera'
**wsrep_cluster_address='gcomm://galera1,galera2'**
**wsrep_node_name='galera3'**
**wsrep_node_address='192.168.245.10'**
wsrep_sst_auth=syncuser:'Qianfeng123!@'
wsrep_sst_method=rsync
重启服务:
[root@galera3 ~]# systemctl restart mysqld
**galera4配置主配置文件my.cnf追加如下内容**
**server-id=4**
binlog_format=row
innodb_file_per_table=1
innodb_autoinc_lock_mode=2
wsrep_on=ON
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
wsrep_cluster_name='galera'
**wsrep_cluster_address='gcomm://galera1,galera2,galera3'**
**wsrep_node_name='galera4'**
**wsrep_node_address='192.168.245.135'**
wsrep_sst_auth=syncuser:'Qianfeng123!@'
wsrep_sst_method=rsync
重启服务:
[root@galera1 ~]# systemctl restart mysqld
查看端口galera端口4567 mysql端口3306
[root@galera1 ~]# ss -auntpl | grep -E '3306|4567'
tcp LISTEN 0 128 *:4567 *:* users:(("mysqld",pid=11068,fd=12))
tcp LISTEN 0 80 :::3306 :::* users:(("mysqld",pid=11068,fd=39))
测试:
```sql
mysql> show status like 'wsrep%';
wsrep_incoming_addresses | 192.168.245.136:3306,192.168.245.135:3306,192.168.245.10:3306|
| wsrep_cluster_size | 3 //表示一共有3个节点,我少配置了一个
```
**阶段测试**
在任何一台机器上写数据,在其他机器上全部会同步
## 脚本操作数据库
方法1
```bash
# mysql -u root -p'Qianfeng123!' -e 'select 5.4*2.8'
# a=2.8
# mysql -u root -p'Qianfeng123!' -e "select 5.4*$a"
# mysql -u root -p'Qianfeng123!' -e "select 5.4*$a;use test;insert t1 set name='lilei';select * from t1"
```
方法2推荐方法
```bash
# cat a.sh
#! /bin/bash
mysql -u root -p'Qianfeng123!' 2>/dev/null <<eof
select 5-2;
use test;
select * from t1;
eof
```
方法3
```bash
# echo 'select 5+8' | mysql -u root -p'Qianfeng123!'
```
## 编译安装(扩展)
注意:官方已经"不提供"安装包下载
清理安装环境
```shell
# yum erase mariadb mariadb-server mariadb-libs mariadb-devel -y
# userdel -r mysql
# rm -rf /etc/my*
# rm -rf /var/lib/mysql
```
创建mysql用户
```shell
# useradd -r mysql -M -s /sbin/nologin
-M 不创建用户家目录
```
安装编译工具
```shell
# yum -y install ncurses ncurses-devel openssl-devel bison gcc gcc-c++ make cmake
```
创建mysql目录
```shell
# mkdir -p /usr/local/{data,mysql,log}
```
编译安装
```shell
# tar xzvf mysql-boost-5.7.27.tar.gz -C /usr/local/
# cd /usr/local/mysql-5.7.27/
# cmake . \
-DWITH_BOOST=boost/boost_1_59_0/ \
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql \
-DSYSCONFDIR=/etc \
-DMYSQL_DATADIR=/usr/local/mysql/data \
-DINSTALL_MANDIR=/usr/share/man \
-DMYSQL_TCP_PORT=3306 \
-DMYSQL_UNIX_ADDR=/tmp/mysql.sock \
-DDEFAULT_CHARSET=utf8 \
-DEXTRA_CHARSETS=all \
-DDEFAULT_COLLATION=utf8_general_ci \
-DWITH_READLINE=1 \
-DWITH_SSL=system \
-DWITH_EMBEDDED_SERVER=1 \
-DENABLED_LOCAL_INFILE=1 \
-DWITH_INNOBASE_STORAGE_ENGINE=1
参数详解:
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql \ 安装目录
-DSYSCONFDIR=/etc \ 配置文件存放 (默认可以不安装配置文件)
-DMYSQL_DATADIR=/usr/local/mysql/data \ 数据目录 错误日志文件也会在这个目录
-DINSTALL_MANDIR=/usr/share/man \ 帮助文档
-DMYSQL_TCP_PORT=3306 \ 默认端口
-DMYSQL_UNIX_ADDR=/tmp/mysql.sock \ sock文件位置用来做网络通信的客户端连接服务器的时候用
-DDEFAULT_CHARSET=utf8 \ 默认字符集。字符集的支持,可以调
-DEXTRA_CHARSETS=all \ 扩展的字符集支持所有的
-DDEFAULT_COLLATION=utf8_general_ci \ 支持的
-DWITH_READLINE=1 \ 上下翻历史命令
-DWITH_SSL=system \ 使用私钥和证书登陆(公钥) 可以加密。 适用与长连接。坏处:速度慢
-DWITH_EMBEDDED_SERVER=1 \ 支持嵌入式数据库
-DENABLED_LOCAL_INFILE=1 \ 从本地倒入数据,不是备份和恢复。
-DWITH_INNOBASE_STORAGE_ENGINE=1 默认的存储引擎,支持外键
```
```shell
# make -j4 && make install
如果安装出错想重新安装不用重新解压只需要删除安装目录中的缓存文件CMakeCache.txt
```
初始化
```shell
进入安装目录修改权限
# chown -R mysql.mysql .
初始化
# ./bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data
初始化,只需要初始化一次,初始化完成之后,一定要记住提示最后的密码用于登陆或者修改密码
```
![image-20200802221725523](assets/image-20200802221725523.png)
```shell
[root@mysql-server ~]# vim /etc/my.cnf 删除旧配置文件之后,再添加如下内容
[mysqld]
basedir=/usr/local/mysql #指定安装目录
datadir=/usr/local/mysql/data #指定数据存放目录
```
启动
```shell
[root@mysql-server ~]# cd /usr/local/mysql
[root@mysql-server mysql]# ./bin/mysqld_safe --user=mysql &
启动之后再按一下回车!即可后台运行
```
登录测试
```shell
[root@mysql-server mysql]# /usr/local/mysql/bin/mysql -uroot -p'GP9TKGgY9i/8'
```
如果需要重新初始化...
```bash
# killall mysqld
# rm -rf /usr/local/mysql/data
# bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data
```
## 破解MySQL密码(扩展)
**MySQL 5.7.5 and earlier:**
```bash
修改配置文件
# vim /etc/my.cnf
[mysqld]
skip-grant-tables # 注意此配置和强密码插件选项配置不能共存
重启服务
登录
# mysql
mysql> update mysql.user set password=password("456") where user="root" and host="localhost";
mysql> flush privileges;
mysql> \q
修改好密码之后注释掉skip-grant-table重启服务即可使用修改后的密码进入数据库
```
**MySQL 5.7.6 and later:**
```bash
1.修改配置
[root@slave1 ~]# vim /etc/my.cnf
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
skip-grant-tables # 注意此配置和强密码插件选项配置不能共存
重启服务
2.MySQL客户端连接服务器并修改密码
# /usr/local/mysql/bin/mysql
mysql> select user,host,authentication_string from mysql.user;
mysql> update mysql.user set authentication_string=password('Qianfeng123!') where user='root';
mysql> flush privileges;
```
**登录测试**
把跳过密码的配置去掉并重新启动MySQL(**新版本不重启服务新密码也直接生效-测试版本为5.7.34**)
```bash
# /usr/local/mysql/bin/mysql -u root -p'Qianfeng123!'
```
## 表名称忽略大小写
```bash
配置文件添加如下配置:
lower_case_table_names=1
```
## 事务
在创建表的时候create table xxxx ( ..........) engine innoDB; 后一句表示创建引擎类型为innoDB它支持事务
开启一个事务: start transaction;
然后你写你的sql语句无论你写多少只要没提交事务这个事务就存在有commit显式提交还有隐式提交你觉得你写的sql语句没有问题时就你就commit; 提交这个事务如果前面你写的sql语句出了问题比如有条sql语句是批量改金币什么的改多了。 Rollback;回滚意思是回到你开启事务时的状态就是说你开启事务后的所有sql操作当作没有发生你重新来过。
注意当一个事务commit,或者rollback就结束了
## MySQL优化扩展
### 慢查询配置
**5.5版本**
[mysqld]
slow-query-log=on
slow_query_log_file=/var/lib/mysql/slowquery.log
long_query_time=1
\#log-queries-not-using-indexes=on //列出没有使用索引的查询语句
**5.7版本**
[mysqld]
slow_query_log=1
slow_query_log_file=/var/log/mysql-slow/slow.log
long_query_time=3
\# mkdir /var/log/mysql-slow/
\# chown mysql.mysql /var/log/mysql-slow/
\# systemctl restart mysqld
查看慢查询日志
测试:BENCHMARK(count,expr)
mysql> SELECT BENCHMARK(500000000,2*3);
### 字符集设置
临时:
mysql> create database db1 CHARACTER SET = utf8;
mysql> create table t1(id int(10)) CHARACTER SET = utf8;
永久:
5.5/5.7版本设置:
[mysqld]
character_set_server = utf8
注意8.0默认使用utf8不需要设置字符集
### 存储引擎
存储引擎就是如何存储数据、如何为存储的数据建立索引和如何更新、查询数据等技术的实现方法。因为在关系数据库中数据的存储是以表的形式存储的,所以存储引擎也可以称为**表类型**(即存储和操作此表的类型)
在Oracle 和SQL Server等数据库中只有一种存储引擎所有数据存储管理机制都是一样的。而MySql数据库提供了多种存储引擎。
用户可以根据不同的需求为数据表选择不同的存储引擎,用户也可以根据自己的需要编写自己的存储引擎。
**查看引擎**
mysql> show engines;
mysql> SHOW VARIABLES LIKE '%storage_engine%';
mysql> show create table t1;
mysql> show table status like 't1';
**关闭不必要的引擎:**
不想用哪个,加上跳过哪个就可以,重启mysql这样也可以优化数据库。
默认如果不想他们启动的话,修改配置文件
\#vim /etc/my.cnf
[mysqld]
skip-mrg_myisam
skip-csv
skip-memory
**临时指定引擎**
mysql> create table innodb1(id int)engine=innodb;
**修改默认引擎**
/etc/my.cnf
[mysqld]
default-storage-engine=INNODB
**修改已经存在的表的引擎**
mysql> alter table t2 engine=myisam;
**MySQL常用存储引擎**:
**MyISAM存储引擎**
由于该存储引擎不支持事务、也不支持外键,所以访问速度较快。因此当对事务完整性没有要求并以访问为主的应用适合使用该存储引擎。
.myi index 存储索引
.myd data 存储数据
.frm 存储表结构
**InnoDB存储引擎**
由于该存储引擎在事务上具有优势即支持具有提交、回滚及崩溃恢复能力等事务特性所以比MyISAM存储引擎占用更多的磁盘空间。
因此当需要频繁的更新、删除操作,同时还对事务的完整性要求较高,需要实现并发控制,建议选择。
大型数据库用innodb
[root@www var]# pwd
/usr/local/mysql/var
[root@www var]# ls ib*
ibdata1 ib_logfile0 ib_logfile1
innodb类型的表的数据存在ibdata1里面不像myisam生成个文件 ib_logfile0 ib_logfile1存放日志
初始是10M,每次增加8M ,初始大小可以指定,要修改配置文件
\#vim /etc/my.cnf
innodb_data_file_path=ibdata1:20M:autoextendmax:1000M
设定初始大小是20M增幅也是8M 设定峰值是1000M,就是指定最大能增加到1000M
innodb_data_home_dir=/data
指定他的存储数据的位置也就是ibdata1的位置
**数据分开存储:**
比放在一块硬盘里访问速度快
默认的数据都保存在var下面可以人为的改变他们的存储位置
只适用于innodb类型.frm文件必须得放在var下不能指定放到别的地方
\#mkdir data 最好是不同的硬盘上
\#chown mysql data
mysql> create table tb1(name char(20)) data directory='/data';
data directory=指定数据文件的位置
**MEMORY**
速度快比myisam快30当数据库重启之后数据就会丢失因为他是存在内存里的.适合于需要快速的访问或临时表。
mysql> create table t20(id int,name char(10)) type=memory; 创建一个memory类型的表
### 客户端连接MySQL数据库速度慢的问题
修改my.cnf配置关闭DNS的反向解析参数
[mysqld]
skip-name-resolve
### 本地客户端不用输入密码登录的配置
[client]
user = root
password = 123
### 调优思路整理
1.数据库设计与规划--以后再修该很麻烦,估计数据量,使用什么存储引擎
2.数据的应用--怎样取数据sql语句的优化
3.mysql服务优化--内存的使用,磁盘的使用(运维)
4.操作系统的优化--内核、tcp连接数量运维
5.升级硬件设备(运维)
**1.数据库设计与规划**
采用什么样的引擎如果网站使用myisam如果事务使用innodb
mysql版本是否需要升级
版本升级原则4.0->4.1->5.0->5.1->5.5
升级工具mysql_upgrade ,如果是innodb类型的表转换成myisam
a数据转myisam引擎
alter table
b复制数据文件到最新数据库中
c , mysql_upgrade
d , 恢复原来的存储引擎
是否用cluster是否需要分区安装方式
操作系统的选择win/linux/unix
**2.数据的应用**
建立索引
在海量查询时少用格式转换如to_char,to_number
多用exists这样语句性能高很多少用in
尽量避免使用is null空值索引失效
**3.磁盘io规划**
raid技术raid0
swap分区最好使用raid0
磁盘分区:
一个库放到一个分区上或一个磁盘上
物理分区:
\#mkdir /data
\#chown mysql.mysql /data
mysql> create table t1(id int,name char(20)) data directory='/data/';
**4.操作系统的优化**
网卡bonding技术
tcp连接数量限制
优化系统打开文件的最大限制
关闭操作系统不必要的服务
**5.mysql服务优化**
show status 看系统的资源
show variables 看变量在my.cnf配置文件里定义的
show processlist 显示系统中正在运行的所有进程。
启用mysql慢查询---分析sql语句找到影响效率的 SQL
查看数据库启动后不会动态更改的值,比如缓冲区大小、字符集、数据文件名称等等:
\# mysqladmin variables
mysql> show variables;
mysql> show variables like "%char%";
查看数据库运行期间动态变化的信息,比如锁等待、当前连接数等等:
\# mysqladmin extended-status
mysql> show status;
mysql> show status like '%slow%';
\# mysqladmin status
Uptime: 4906 Threads: 1 Questions: 15 Slow queries: 0 Opens: 15 Flush tables: 1 Open tables: 8 Queries per second avg: 0.3
\# mysqladmin -i 2 status //-i 2 #两秒钟刷新一次
Questions 所有查询的数量
Opens 服务器已经打开的数据库表的数量
Open_tables 通过命令打开的表的数量
mysql> show open tables;
查看参数用法和当前使用的参数值:
5.7
\# mysqld -v --help | grep -A 2 default-character
**实际上绝大多数参数不是经常需要用户调整的**
**对查询进行缓存:**
query_cache_size 使用多大内存来缓存查询语句
query_cache_limit 超过此大小的查询将不缓存
query_cache_wlock_invalidate 当有其他客户端正在对表进程写操作时如果查询在query cache中是返回cache结果还是等写操作完成再读表获取结果
query_cache_min_res_unit 缓存块儿的最小大小,如果块儿大但是查询的数据都是小数据,会导致内存碎片增多,浪费内存
设置举例:
\#vim /etc/my.cnf
query_cache_size=10M
重启服务,查看# /usr/libexec/mysqld -v --help | grep query_cache_size
Qcache_free_blocks 说明缓存太大了。缓存中相邻内存的个数。数目大说明可能有碎片。FLUSH QUERY CACHE会对缓存中的碎片进行整理从而得到一个空闲块。
Qcache_total_blocks: 缓存中块儿总数
缓存碎片率计算:
Qcache_free_blocks / Qcache_total_blocks * 100%
如果缓存碎片率超过20%就要使用FLUSH QUERY CACHE整理缓存碎片或尝试减小块儿大小
Qcache_free_memory 缓存中的空闲内存
Qcache_hits 每次查询在缓存中命中时就增大
Qcache_inserts 每插入一个查询时就增大。命中次数除以插入次数就是命中率。
Qcache_lowmem_prunes 缓存出现内存不足并且必须要进行清理以便为更多查询提供空间的次数。这个数字最好长时间看;如果这个数字在不断增长就表示可能碎片非常严重,或者内存很少
Qcache_hits/Qcache_inserts 命中率 命中率低,可能因为写操作太频繁
缓存利用率:
(query_cache_size - Qcache_free_memory)/query_cache_size * 100%
缓存利用率在25%以下说明query_cache_size设置过大
缓存利用率在80%以上且 Qcache_lowmem_prunes > 50说明query_cache_size设置过小或者碎片过多。
强制限制mysql资源设置:
max_connections = 200 客户端并发连接数
connect_timeout=
临时表空间大小order by和group by时把数据放到临时表里。
tmp_table_size 占的是内存的大小,如果太小在排序时会出错
created_tmp_tables 创建临时表的数量
max_tmp_tables=32
tmpdir=/tmp 硬盘上临时表所在的位置
**myisam引擎**
*key_buffer_size*
说明: 指定索引缓冲区的大小它决定索引处理的速度尤其是索引读的速度。只对MyISAM表起作用。即使你不使用MyISAM表但是内部的临时磁盘表是MyISAM表也要使用该值。可以使用检查状态值created_tmp_disk_tables得知详情。对于1G内存的机器如果不使用MyISAM表推荐值是16M8-64M
使用方法:
mysql5.1 以前只允许使用一个系统默认的 key_buffer
mysql5.1 以后提供了多个 key_buffer,可以将指定的表索引缓存入指定的key_buffer,这样可以更小的降低线程之间的竞争,相关语法如下:
临时生效:
建立索引缓存:
mysql> set global hot_cache2.key_buffer_size=128*1024; //global表示对新的连接立即生效host_cache2是新的key_buffer名称大小可以随时更改
把t1,t2表的索引关联到指定的索引缓存中:
mysql> cache index t1,t2 in hot_cache2;
+---------+--------------------+----------+----------+
| Table | Op | Msg_type | Msg_text |
+---------+--------------------+----------+----------+
| test.t1 | assign_to_keycache | status | OK |
| test.t2 | assign_to_keycache | status | OK |
+---------+--------------------+----------+----------+
预装表t1t2的所有索引
mysql> load index into cache t1,t2;
+---------+--------------+----------+----------+
| Table | Op | Msg_type | Msg_text |
+---------+--------------+----------+----------+
| test.t1 | preload_keys | status | OK |
| test.t2 | preload_keys | status | OK |
+---------+--------------+----------+----------+
删除键高速缓冲,将其大小设置为零:
mysql> set global host_cache2.key_buffer_size=0;
不能删除默认key_buffer:
mysql> set global key_buffer_size=0;
ERROR 1438 (HY000): Cannot drop default keycache
永久生效:
cache index在一个表和key_buffer之间建立联系但每次服务器重启时key_buffer中的数据将清空。如果想每次服务器重启是相应的索引能自动放到key_buffer中
可以在配置文件中设置init-file选项来制定包含cache index语句的文件路径然后在对应的文件中写入cache index语句。
\#vim /etc/my.cnf //添加下面几行
key_buffer_size = 4G
hot_cache.key_buffer_size = 2G
cold_cache.key_buffer_size = 2G
init_file=/path/to/data-directory/mysqld_init.sql
\# cat /path/to/data-directory/mysqld_init.sql
cache index test.t1 in hot_cache;
cache index test.t2 in cold_cache;
相关状态参数值:
mysql> show status like "Key_read";
Key_read_requests 请求总数
Key_reads 代表命中磁盘的请求个数
(key_read_requests - key_read)/key_read_requests命中率
*table_open_cache*table_cache已经不能使用表高速缓存缓存表的数量
table_open_cache 打开表缓存总数如果经常对一些表进行操作希望将读过的表放入到cache中减少对磁盘的读取次数。可以检查峰值时间的状态值Open_tables和Opened_tables.
open_tables 通过命令打开的表的数量
opened_tables 曾经打开过的表的数量这个值累加这个值再增加说明表的缓存要设置大些用flush tables清空表缓存的时候这个不会改变
表缓存没有命中的数量。如果该值很大你可能需要增加table_cache的数值。典型地你可能想要这个值每秒打开的表数量少于1或2。
如果你发现open_tables等于table_open_cache并且opened_tables在不断增长那么你就需要增加table_open_cache的值了。
在mysql默认安装情况下table_cache的值在2G内存以下的机器中的值默认时256到512,对于有1G内存的机器推荐值是128256。
设置技巧:
可以通过检查 mysqld 的状态变量 Opened_tables 确定表缓存是否太小:
mysql> show status like "open_tables"; //如果值很大,即使你没有发出许多 FLUSH TABLES 语句,也应增加表缓存的大小。
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Open_tables | 10 |
+---------------+-------+
mysql> flush tables; //清空表缓存
**innodb引擎**
*innodb-buffer-pool-size* //缓存 InnoDB 数据和索引的内存缓冲区的大小
\# /usr/libexec/mysqld -v --help | grep "\-\-innodb-buffer-pool-size" -A 2 //-A表示包含关键字的行和他后面的两行
--innodb-buffer-pool-size=#
The size of the memory buffer InnoDB uses to cache data
and indexes of its tables.
这个值设得越高,访问表中数据需要得磁盘 I/O 越少。在一个专用的数据库服务器上,你可以设置这个参数达机器物理内存大小的 80%。尽管如此,还是不要把它设置得太大,因为对物理内存的竞争可能在操作系统上导致内存调度。
myisam的key_buffer_size只缓存索引键而innodb-buffer-pool-size却是同时为数据块和索引块做缓存这个特性和ORACLE是一样的。
创建表空间文件:
[mysqld]
innodb_data_file_path=ibdata1:10M:autoextend
这个设置配置一个可扩展大小的尺寸为10MB的单独文件名为ibdata1。没有给出文件的位置所以默认的是在MySQL的数据目录内。
如果你对最后的数据文件指定autoextend选项。如果数据文件耗尽了表空间中的自由空间InnoDB就扩展数据文件。扩展的幅度是每次8MB。
要为一个自动扩展数据文件指定最大尺寸请使用max属性。
下列配置允许ibdata1涨到极限的500MB
[mysqld]
innodb_data_file_path=ibdata1:10M:autoextend:max:500M
InnoDB默认地在MySQL数据目录创建表空间文件。要明确指定一个位置请使用innodb_data_home_dir选项。比如要使用两个名为ibdata1和ibdata2的文件但是要把他们创建到/ibdata像如下一样配置InnoDB
[mysqld]
innodb_data_home_dir = /ibdata //注意设置这个选项的时候,如果第一次起不来需要删除这次产生的表空间文件再次重启
innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend
为每个表生成一个表空间文件:
innodb_file_per_table=1
重启mysql
**其他参数**
skip-locking(已经用下面参数代替)
skip-external-locking=on
取消文件系统的外部锁,减少出错几率增强稳定性
skip-name-resolve
关闭mysql的dns反查功能。速度快很多!
选项就能禁用DNS解析连接速度会快很多。不过这样的话就不能在My中使用主机SQL的授权表名了而只能用ip格式。
wait_timeout=10 终止空闲时间超过10秒的链接避免长连接
max_connect_errors=10 //10次连接失败就锁定使用flush hosts 解锁,
或mysqladmin flush-hosts解锁
innodb_additional_mem_pool_size
InnoDB 用来存储数据目录信息和其它内部数据结构的内存池的大小。默认值是1MB。应用程序里的表越多,你需要在这里分配越多的内存。如果 InnoDB 用光了这个池内的内存,InnoDB 开始从操作系统分配内存,并且往 MySQL 错误日志写警告信息。没有必要给这个缓冲池分配非常大的空间,在应用相对稳定的情况下,这个缓冲池的大小也相对稳定。
innodb_lock_wait_timeout:
Mysql 可以自动的监测行锁导致的死锁并进行相应的处理,但是对于表锁导致的死锁不能自动的监测,
所以该参数主要被用来在出现类似情况的时候对锁定进行回滚。默认值是 50 秒,根据应用的需要进行调整。
innodb_support_xa:
通过该参数设置是否支持分布式事务,默认值是 ON 或者 1,表示支持分布式事务。如果确认应用中不需要使用分布式事务,则可以关闭这个参数,减少磁盘刷新的次数并获得更好的 InnoDB 性能。
分布式事务:
像这种情况一定需要分布式的事务要不都提交要么都回滚。在任何一个节点出问题都会造成严重的结果1 xiaozhang的帐号被扣款但是xiaoli没有收到钱2 xiaozhang的帐号没有被扣款但是xiaoli收到钱了。
innodb_doublewrite:
默认地,InnoDB 存储所有数据两次,第一次存储到 doublewrite 缓冲,然后存储到确实的数据文件。如果对性能的要求高于对数据完整性的要求,那么可以通过--skip-innodb-doublewrite 关闭这个设置。
innodb_log_file_size:
在高写入负载尤其是大数据集的情况下很重要。这个值越大则性能相对越高,但是要注意到可能会增加恢复时间。