# 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软件采用了GPL(GNU通用公共许可证),定义了在不同情况下可以用软件作的事和不可作的事。数据库服务器具有快速、可靠和易于使用。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语言介绍 SQL(Structured 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、等价于没有任何值、是未知数。 2、NULL与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、经验值等。 两种类型分类: 分类1:tinyint 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没有字符集的概念,对其排序和比较都是按照二进制值进行对比。 BINARY(N)和VARBINARY(N)中的N指的是字节长度,而CHAR(N)和VARCHAR(N)中N指的是的字符长度。对于BINARY(10) ,其可存储的字节固定为10,而对于CHAR(10) ,其可存储的字节视字符集的情况而定。 **文本类型(了解)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.5,5.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; ``` **unique(key)** ```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 key(key)** **特性** ​ 每张表里只能有一个主键 ​ 不能为空,而且唯一 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.5和5.7的%不包括127.0.0.1和localhost (-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 - 热备份:数据库启动同时给客户端提供服务的情况下 - 冷备份:数据库要关掉或者不能给客户端提供服务 **备份方案** - 完全备份 - 增量备份 - 差异备份 file://C:/Users/86186/AppData/Local/Temp/.UKVV11/1.png 完整备份: 每次都将所有数据(不管自第一次备份以来有没有修改过),进行一次完整的复制,备份后会清除文件的存档属性,方便日后增量备份或者差异备份进行版本比较。 特点:占用空间大,备份速度慢,但恢复时一次恢复到位,相对恢复速度快。 增量备份: 在第一次完整备份之后,第二次开始每次都将添加了存档属性的文件进行备份,并且在备份之后再把这些存档属性清除。为什么要清除存档属性呢?这就是为了下一次备份的时候判断是否有文件变化,因为用户在每次备份以后修改这些被清除存档属性的文件,存档属性就会自动加上,相当于用户告诉系统,这些文件有变化,你下一次就备份这些文件,其他没有存档属性的就不需要备份,这就是增量备份的工作机制。相当于机器人把地板打扫干净了,你踩过,就会有脚印(增加标记),下次机器人就把脚印记录下来,并且把脚印打扫干净(清除标记),始终保持地板干净。机器人每次记录并打扫的脚印就相当于每次增量备份的内容) 特点:因每次仅备份自上一次备份(注意是上一次,不是第一次)以来有变化的文件,所以备份体积小,备份速度快,但是恢复的时候,需要按备份时间顺序,逐个备份版本进行恢复,恢复时间长。    差异备份: 在第一次完整备份之后,第二次开始每次都将所有文件与第一次完整备份的文件做比较,把自第一次完整备份以来所有修改过的文件进行备份,且以后每次备份都是和第一次完整备份进行比较(注意是第一次,不是上一次),备份自第一次完整备份以来所有的修改过的文件。因此,差异备份在备份完毕之后不需要清除文件的存档属性,因为这些文件和下一次备份没有什么关系,它仅仅和第一次完整备份的数据进行比较(第一次完整备份之后是清除存档属性的)。相当于第一次机器人把地板打扫干净了,你踩过,就会有脚印,机器人就把脚印记录下来,但不打扫,下次你又有踩脏的,机器人就把你这几次所有踩脏的地方都记录下来,始终不打扫,每次都这样。机器人每次记录的内容就相当于差异备份的内容) 特点:占用空间比增量备份大,比完整备份小,恢复时仅需要恢复第一个完整版本和最后一次的差异版本,恢复速度介于完整备份和增量备份之间。 简单的讲,完整备份就是不管三七二十一,每次都把指定的备份目录完整的复制一遍,不管目录下的文件有没有变化;增量备份就是每次将之前(第一次、第二次、直到前一次)做过备份之后有变化的文件进行备份;差异备份就是每次都将第一次完整备份以来有变化的文件进行备份。 举例:   假设指定备份目录周一包含A、B、C三个文件。周一的时候,做了完整备份。周二新增了D文件,同时A文件发生变化,变成A1文件;周三新增了E文件,同时A文件变成了A2,B文件变成B1;周四新增了F文件,A2变成了A3,D变成了D1,同时删掉了C文件。      不同备份方式下的备份情况(假设每天做一次备份):   完整备份:周一,备份ABC三个文件;周二,备份A1、B、C、D四个文件;周三,备份A2、B1、C、D、E五个文件;   周四,备份A3、B1、D1、E、F五个文件。      增量备份:周一,备份ABC三个文件,完整备份;周二,备份与周一相比有变化的文件,即备份A1和D两个文件;周三,备份与之前所有版本相比有变化的文件,即备份A2,B1,E三个文件;周四,备份与之前所有版本相比有变化的文件,即备份A3,D1,F三个文件并删除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 servers,does 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'; ``` 问题2:mysql 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/ [file://C:/Users/86186/AppData/Local/Temp/.UKVV11/1.png]() **准备环境** ```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 < 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生成3个文件, ib_logfile0 ib_logfile1存放日志 ​ 初始是10M,每次增加8M ,初始大小可以指定,要修改配置文件 ​ \#vim /etc/my.cnf ​ innodb_data_file_path=ibdata1:20M:autoextend:max: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表,推荐值是16M(8-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 | ​ +---------+--------------------+----------+----------+ ​ 预装表t1,t2的所有索引: ​ 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内存的机器,推荐值是128-256。 ​ 设置技巧: ​ 可以通过检查 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: ​ 在高写入负载尤其是大数据集的情况下很重要。这个值越大则性能相对越高,但是要注意到可能会增加恢复时间。