MySQL是一个关系型数据库管理系统,由瑞典MySQL AB(创始人Michael Widenius)公司开发,2008被Sun收购(10亿美金),2009年Sun被Oracle收购。MariaDB
MariaDB基于事务的Maria存储引擎,替换了MySQL的MyISAM存储引擎; 它使用了Percona的 XtraDB代替了InnoDB存储引擎。
MySQL是一种关联数据库管理系统,将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。
MySQL是开源的,所以你不需要支付额外的费用。
MySQL是可以定制的,采用了GPL(GNU General Public License)协议,你可以修改源码来开发自己的MySQL系统。
MySQL支持大型的数据库。可以处理拥有上千万条记录的大型数据库。
MySQL支持大型数据库,支持5000万条记录的数据仓库,32位系统表文件最大可支持4GB,64位系统支持最大的表文件为8TB。
MySQL使用标准的SQL数据语言形式。
MySQL可以允许于多个系统上,并且支持多种语言。这些编程语言包括C、C++、C#、Python、Java、Perl、PHP、Eiffel、Ruby和Tcl等。
数据库内部结构和原理
数据库建模优化
数据库索引建立
SQL语句优化
SQL编程(自定义函数、存储过程、触发器、定时任务)
mysql服务器的安装配置
数据库的性能监控分析与系统优化
各种参数常量设定
主从复制
分布式架构搭建、垂直切割和水平切割
数据迁移
容灾备份和恢复
shell或python等脚本语言开发
对开源数据库进行二次开发
官网:https://www.mysql.com
然后,点击MySQL Community(GPL) Downloads
MySQL分为社区版(Community Server)和企业版(Enterprise Server)
如果安装Windows 系统下MySQL ,推荐下载MSI安装程序;点击Go to Download Page进行下载即可
Windows下的MySQL安装有两种安装程序
l mysql-installer-web-community-5.7.28.0.msi 下载程序大小:19020KB;安装时需要联网安装组件。
l mysql-installer-community-5.7.28.0.msi 下载程序大小:504828KB;安装时离线安装即可。推荐。
安装方式 | 特点 |
---|---|
rpm | 安装简单,灵活性差,无法灵活选择版本、升级 |
rpm repository | 安装包极小,版本安装简单灵活,升级方便,需要联网安装 |
通用二进制包 | 安装比较复杂,灵活性高,平台通用性好 |
源码包 | 安装最复杂,时间长,参数设置灵活,性能好 |
目前最新版本为8.0.18,发布时间2019.10.14;8.0.0在2016.9.12日就发布了。
本课程中使用5.7版本。选择下图中⑤来到以前版本下载页面。
这里不能直接选择CentOS7系统的版本,所以选择与之对应的Red Hat Enterprise Linux 7
直接点Download下载RPM Bundle全量包。包括了所有下面的组件。不需要一个一个下载了。
rpm -qa | grep -i mariadb CentOS7使用这个
-i忽略大小写
卸载MySQL; --nodeps 排除依赖,否则别的软件依赖mysql,无法删除
rpm -e --nodeps mariadb-libs
rpm -qa|grep libaio
rpm -qa|grep net-tools
rpm -ivh mysql-community-common-5.7.28-1.el7.x86_64.rpm
rpm -ivh mysql-community-libs-5.7.28-1.el7.x86_64.rpm
rpm -ivh mysql-community-client-5.7.28-1.el7.x86_64.rpm
rpm -ivh mysql-community-server-5.7.28-1.el7.x86_64.rpm
如在检查工作时,没有检查mysql依赖环境在安装mysql-community-server会报错
rpm 是Redhat Package Manage缩写,通过RPM的管理,用户可以把源代码包装成以rpm为扩展名的文件形式,易于安装。
-i, --install 安装软件包
-v, --verbose 提供更多的详细信息输出
-h, --hash 软件包安装的时候列出哈希标记 (和 -v 一起使用效果更好),展示进度条
![image-20220803111721000]/image-20220803111721000.png)
为了保证数据库目录为与文件的所有者为 mysql 登录用户,如果你是以 root 身份运行 mysql 服务,需要执行下面的命令初始化:
mysqld --initialize --user=mysql
另外 --initialize 选项默认以“安全”模式来初始化,则会为 root 用户生成一个密码并将该密码标记为过期,登录后你需要设置一个新的密码
查看密码:cat /var/log/mysqld.log
启动:systemctl start mysqld.service
关闭:systemctl stop mysqld.service
重启:systemctl restart mysqld.service
查看状态:systemctl status mysqld.service
systemctl list-unit-files|grep mysqld.service
systemctl enable mysqld.service
systemctl disable mysqld.service
因为初始化密码默认是过期的,所以查看数据库会报错
修改密码:ALTER USER ‘root’@‘localhost’ IDENTIFIED BY ‘new_password’; 但新密码太简单会报错
ALTER USER ‘root’@‘localhost’ IDENTIFIED BY ‘root’;
参数 | 路径 | 解释 | 备注 |
---|---|---|---|
–basedir | /usr/bin | 相关命令目录 | mysqladmin mysqldump等命令 |
–datadir | /var/lib/mysql/ | mysql数据库文件的存放路径 | |
–plugin-dir | /usr/lib64/mysql/plugin | mysql插件存放路径 | |
–log-error | /var/log/mysqld.log | mysql错误日志路径 | |
–pid-file | /var/run/mysqld/mysqld.pid | 进程pid文件 | |
–socket | /var/lib/mysql/mysql.sock | 本地连接时用的unix套接字文件 | |
/usr/share/mysql | 配置文件目录 | mysql脚本及配置文件 | |
/etc/systemd/system/multi-user.target.wants/mysqld.service | 服务启停相关脚本 | ||
/etc/my.cnf | mysql配置文件 | cat /etc/my.cnf |
show variables like ‘%char%’;
vim /etc/my.cnf
[client]
default-character-set=utf8
[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci
systemctl restart mysqld
alter database mydb character set 'utf8';
alter table mytbl convert to character set 'utf8';
但是原有的数据如果是用非’utf8’编码的话,数据本身编码不会发生改变。
已有数据需要导出或删除,然后重新插入。
show variables like 'character%';
show variables like '%char%';
create user zhang3 **identified** by '123123';
select * from mysql.user \G; 以列的方式显示数据
select host,user,authentication_string,select_priv,insert_priv,drop_priv from mysql.user;
查询特定字段
% 表示所有远程通过 TCP方式的连接
IP 地址 如 (192.168.1.2,127.0.0.1) 通过制定ip地址进行的TCP方式的连接
- 机器名 通过制定网络中的机器名进行的TCP方式的连接
::1 IPv6的本地ip地址,等同于IPv4的 127.0.0.1
localhost 本地方式通过命令行方式的连接 ,比如mysql -u xxx -p xxx 方式的连接。
同一用户通过不同方式链接的权限是不一样的。
所有密码串通过 password(明文字符串) 生成的密文字符串。加密算法为MYSQLSHA1,不可逆 。
mysql 5.7 的密码保存到 authentication_string 字段中不再使用password 字段。
为该用户所拥有的权限。
set password =password(‘123456’)
修改某个用户的密码:
必须使用root 用户
update mysql.user set authentication_string=password('111111') where user='zhang3';
flush privileges;
#所有通过user表的修改,必须用该命令才能生效。
drop user zhang3 ; 推荐使用!
grant 权限1,权限2,…权限n on 数据库名称.表名称 to 用户名@用户地址 identified by ‘连接口令’;
该权限如果发现没有该用户,则会直接新建一个用户。
比如:
grant select,insert,delete,update on atguigudb.* to li4@localhost identified by ‘123’;
# 必须有li4 用户才行!
grant all privileges on . to joe@‘%’ identified by ‘123’;
revoke 权限1,权限2,…权限n on 数据库名称.表名称 from 用户名@用户地址 ;
REVOKE ALL PRIVILEGES ON . FROM joe@‘%’; #收回全库全表的所有权限
REVOKE select,insert,update,delete ON . FROM joe@‘%’;
#收回mysql库下的所有表的插删改查权限
查看当前用户权限:show grants;
查看某用户的全局权限:select * from mysql.user ;
grant all privileges on . to root@‘%’ identified by ‘root’;
# ping 192.168.200.168 -t
systemctl start firewalld.service
systemctl status firewalld.service
systemctl stop firewalld.service
systemctl enable firewalld.service
systemctl disable firewalld.service
查看开放的端口号
firewall-cmd --list-all
设置开放的端口号 生成环境!
firewall-cmd --add-service=http --permanent
firewall-cmd --add-port=80/tcp --permanent
firewall-cmd --add-port=3306/tcp --permanent
重启防火墙
firewall-cmd --reload
select * from mysql.user where user='root' and host='%';
grant all privileges on *.* to root@'%' identified by 'root';
sql_mode设置是否允许一些非法操作,比如允许一些非法数据的插入,数据查询等。
在生产环境必须将这个值设置为严格模式,所以开发、测试、生产环境的数据库也必须要设置,这样在开发测试阶段就可以发现问题。
select @@GLOBAL.sql_mode;全局的sql_mode
select @@SESSION.sql_mode;会话级别sql_mode
CREATE TABLE mytbl2(id INT,NAME VARCHAR(16),age INT,dept INT);
INSERT INTO mytbl2 VALUES(1,'zhang3',33,101);
INSERT INTO mytbl2 VALUES(2,'li4',34,101);
INSERT INTO mytbl2 VALUES(3,'wang5',34,102);
INSERT INTO mytbl2 VALUES(4,'zhao6',34,102);
INSERT INTO mytbl2 VALUES(5,'tian7',36,102);
#查询每个部门年龄最大的人
正确的语句:
SELECT m.* FROM mytbl2 m INNER JOIN(SELECT dept,MAX(age) maxage FROM mytbl2 GROUP BY dept) AS ab
ON ab.dept=m.dept AND m.age=ab.maxage
注意: MySQL5.7默认已经设置了ONLY_FULL_GROUP_BY。
SET GLOBAL sql_mode = ‘modes…’;
SET SESSION sql_mode = ‘modes…’;
[mysqld]
#set the SQL mode to strict
#sql-mode="modes..."
sql-mode = "ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
show variables like ‘sql_mode’;
set sql_mode=‘ONLY_FULL_GROUP_BY’;
ONLY_FULL_GROUP_BY:对于GROUP BY聚合操作,如果在SELECT中的列,没有在GROUP BY中出现,那么这个SQL是不合法的,因为列不在GROUP BY从句中
NO_AUTO_VALUE_ON_ZERO:该值影响自增长列的插入。默认设置下,插入0或NULL代表生成下一个自增长值。如果用户希望插入的值为0,而该列又是自增长的,那么去掉该选项。
STRICT_ALL_TABLES,STRICT_TRANS_TABLES
对于支持事务的表,这两种模式是一样的:如果发现某个值缺失或非法,MySQL将抛出错误,语句会停止运行并回滚。
对于不支持事务的表,这两种模式的效果:
如果在插入或修第一个数据行时就发现某个值非法或缺失,那该语句直接抛错,语句停止执行。这个和支持事务的数据表行为时一样的。
如果在插入或修改第n个(n>1)数据行时才发现错误,那就会出现下面的情况:
2.1 在STRICT_ALL_TABLES模式下,停止语句执行,存在部分更新的问题
2.2 在STRICT_TRANS_TABLES模式下,MySQL将继续执行该语句避免“部分更新问题”,对每个非法值将其转换为最接近的合法值。
NO_ZERO_IN_DATE:在严格模式下,不允许日期和月份为零
NO_ZERO_DATE:设置该值,mysql数据库不允许插入零日期,插入零日期会抛出错误而不是警告。
ERROR_FOR_DIVISION_BY_ZERO:在INSERT或UPDATE过程中,如果数据被零除,则产生错误而非警告。如果未给出该模式,那么数据被零除时MySQL返回NULL
NO_AUTO_CREATE_USER:禁止GRANT创建密码为空的用户
NO_ENGINE_SUBSTITUTION:如果需要的存储引擎被禁用或不存在,那么抛出错误。不设置此值时,用默认的存储引擎替代
和其它数据库相比,MySQL有点与众不同,它的架构可以在多种不同场景中应用并发挥良好作用。主要体现在存储引擎的架构上,插件式的存储引擎架构将查询处理和其它的系统任务以及数据的存储提取相分离。
这种架构可以根据业务的需求和实际需要选择合适的存储引擎。
最上层是一些客户端和连接服务,包含本地socket通信和大多数基于客户端/服务端工具实现的类似于tcp/ip的通信。
主要完成一些类似于连接处理、授权认证、及相关的安全方案。
在该层上引入了线程池的概念,为通过认证安全接入的客户端提供线程。
同样在该层上可以实现基于SSL的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作权限。
第二层架构主要完成大多数的核心服务功能,如SQL接口,并完成缓存的查询,SQL的分析和优化及部分内置函数的执行。
所有跨存储引擎的功能也在这一层实现,如过程、函数等。
在该层,服务器会解析查询并创建相应的内部解析树,并对其完成相应的优化:如确定查询表的顺序,是否利用索引等,最后生成相应的执行操作。
如果是select语句,服务器还会查询内部的缓存。如果缓存空间足够大,这样在解决大量读操作的环境中能够很好的提升系统的性能。
2.1 Management Serveices & Utilities: 系统管理和控制工具
2.2 SQL Interface: SQL接口
接受用户的SQL命令,并且返回用户需要查询的结果。比如select from就是调用SQL Interface
2.3 Parser: 解析器
2.4 Optimizer: 查询优化器。
2.5 Cache和Buffer: 查询缓存。
如果查询缓存有命中的查询结果,查询语句就可以直接去查询缓存中取数据。
这个缓存机制是由一系列小缓存组成的。比如表缓存,记录缓存,key缓存,权限缓存等
存储引擎层,存储引擎真正的负责了MySQL中数据的存储和提取,服务器通过API与存储引擎进行通信。不同的存储引擎具有的功能不同,这样我们可以根据自己的实际需要进行选取。后面介绍MyISAM****和InnoDB
数据存储层,主要是将数据存储在运行于裸设备的文件系统之上,并完成与存储引擎的交互。
了解查询语句底层执行的过程:;;;;;;查看是否开启计划。
新增一行:query_cache_type=1
重启mysql:systemctl restart mysqld
show variables like ‘%profiling%’;
set profiling=1;
执行语句两次:select * from mydb.mytbl where id=1 ;
显示最近执行的语句
show profiles;
show profile cpu,block io for query 6;
执行编号7时,比执行编号6时少了很多信息,从下面截图中可以看出查询语句直接从缓存中获取数据;
注意:SQL必须是一致的,否则,不能命中缓存。
如果对数据库表进行 insert ,update ,delete 这个时候,缓存会失效!
如:select * from mydb.mytbl where id=2 和 select * from mydb.mytbl where id>1 and id<3 虽然查询结果一致,但并没有命中缓存。
mysql的查询流程大致是:
首先,mysql客户端通过协议与mysql服务器建连接,发送查询语句,先检查查询缓存,如果命中,直接返回结果,否则进行语句解析,也就是说,在解析查询之前,服务器会先访问查询缓存(query cache)——它存储SELECT语句以及相应的查询结果集。
如果某个查询结果已经位于缓存中,服务器就不会再对查询进行解析、优化、以及执行。它仅仅将缓存中的结果返回给用户即可,这将大大提高系统的性能。
语法解析器和预处理:首先mysql通过关键字将SQL语句进行解析,并生成一颗对应的“解析树”。
mysql解析器将使用mysql语法规则验证和解析查询;
预处理器则根据一些mysql规则进一步检查解析树是否合法。
查询优化器当解析树被认为是合法的了,并且由优化器将其转化成执行计划。
一条查询可以有很多种执行方式,最后都返回相同的结果。优化器的作用就是找到这其中最好的执行计划。
然后,mysql默认使用的BTREE索引,并且一个大致方向是:无论怎么折腾sql,至少在目前来说,mysql只少用到表中的一个索引。
数据结构有很多种,一般来说,按照数据的逻辑结构对其进行简单的分类,包括线性结构和非线性结构两类。
线性结构:
线性结构作为最常用的数据结构,其特点是数据元素之间存在一对一的线性关系。
线性结构有两种不同的存储结构,即顺序存储结构和链式存储结构。
顺序存储的线性表称为顺序表,顺序表中的存储元素是连续的
链式存储的线性表称为链表,链表中的存储元素不一定是连续的,元素节点中存放数据元素以及相邻元素的地址信息
线性结构常见的有:数组、链表、队列和栈。
非线性结构:
非线性结构包括:二维数组,多维数组,树结构,图结构
同一问题可用不同算法解决,而一个算法的质量优劣将影响到算法乃至程序的效率。算法分析的目的在于选择合适算法和改进算法。
http://www.99cankao.com/algebra/log2.php
常见的算法时间复杂度由小到大依次为:O—理解为一个函数
Hash 最好,次之平衡树!
算法:解决问题的方案
时间复杂度:是指执行算法所需要的基本运算次数。
空间复杂度:是指执行算法所需要的内存空间。
类似于时间复杂度的讨论,一个算法的空间复杂度(Space Complexity)定义为该算法所耗费的存储空间,它也是问题规模n的函数。
空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度。有的算法需要占用的临时工作单元数与解决问题的规模n有关,它随着n的增大而增大,当n较大时,将占用较多的存储单元。
在做算法分析时,主要讨论的是时间复杂度。从用户使用体验上看,更看重的程序执行的速度。一些缓存产品(redis, memcache)和算法(基数排序)本质就是用空间换时间。
加速查找速度的数据结构,常见的有两类:
(1) 哈希,例如HashMap,查询/插入/修改/删除的平均时间复杂度都是O(1);
(2) 树,例如平衡二叉搜索树,查询/插入/修改/删除的平均时间复杂度都是O(log2N);
可以看到,不管是读请求,还是写请求,哈希类型的索引,都要比树型的索引更快一些,
那为什么,索引结构要设计成树型呢?
索引:数据库的索引 -树!
想想范围/排序等其它SQL条件:
哈希型的索引,时间复杂度会退化为O(n)而树型的“有序”特性,依然能够保持O(log2N) 的高效率。
备注:InnoDB并不支持哈希索引。
https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
二叉树的特点:
1、一个节点只能有两个子节点,也就是一个节点度不能超过2
2、左子节点 小于 本节点;右子节点大于等于 本节点,比我大的向右,比我小的向左
这种方式查找:时间复杂度会再次上升
* 第1种情况 如果id的值是持续递增的话,会是什么样的结构? | |
---|---|
* 第2种情况 |
AVL树全称G.M. Adelson-Velsky和E.M. Landis,这是两个人的人名。
在插入数据的时候会自动发生n多次旋转操作,旋转操作会消耗一定的性能!旋转的目的就是保证这个棵数的平衡。平衡二叉树要求左子树与左子树的高度差不能超过1
https://www.cs.usfca.edu/~galles/visualization/AVLtree.html
问题:
在构建二叉树时,需要多次进行i/o操作(海量数据存在数据库或文件中),节点海量,构建二叉树时,速度有影响。
节点海量,也会造成二叉树的高度很大,会降低操作速度。
解决问题:
我们为了减少磁盘IO的次数,就必须降低树的深度,将“瘦高”的树变得“矮胖”。
(1)每个节点存储多个元素
(2)摒弃二叉树结构,采用多叉树
红黑树:
插入顺序:2,1,4,5,3,6
当再次插入7的时候,这棵树就会发生旋转
在这个棵严格的平台树上又进化为“红黑树”{是一个非严格的平台树 左子树与左子树的高度差不能超过1},红黑树的长子树只要不超过短子树的两倍即可!
B-Tree树即B树,B即Balanced,平衡的意思。
B-Tree即B树,Balance Tree,平衡树。
2-3树是最简单的B树结构。
B树的阶:节点的最多子节点个数。比如2-3树的阶是3,2-3-4树的阶是4。
B树通过重新组织节点,降低树的高度,并且减少IO读写次数来提升效率。
关键字集合分布在整颗树中,即叶子节点和非叶子节点都存放数据。
https://www.cs.usfca.edu/~galles/visualization/BTree.html
黄色:指针,存储子节点的信息地址
红色:键值,表中记录的主键
蓝色:数据,记录表中除主键外的数据
以上图为例:若查询的数值为5:
第一次磁盘IO:根据根节点找到磁盘块1,读入内存,执行二分查找,比17小,根据指针P1,找左子树;
第二次磁盘IO:找到磁盘块2,读入内存,执行二分查找,比8小,根据指针P1,找左子树;
第三次磁盘IO:找到磁盘块5,读入内存,执行二分查找,找到5,终止。
整个过程中,我们可以看出:BTree相对于平衡二叉树降低了树的高度,缩减了节点个数,减少了I/O操作,提高了查询效率
还可以优化!让每个磁盘块存储更多的指针
B+Tree 即B+树:
B+树是B树的升级版本,区别是所有数据只出现在叶子结点中,即叶只有叶子节点存放数据,非叶子节点只是叶子结点中数据的键值和指针。
所有的叶子结点中包含了全部数据信息,及指向含这些数据记录的指针,叶子节点之间通过指针相连,且叶子结点本身依键值的大小自小而大顺序链接。
由于B+树的非叶子节点不存储数据,因此每个节点可以存储更多的信息,假设每个节点能存储4个键值和指针信息,则变成B+树后其结构如下图所示:
https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html
由于B+树的非叶子节点只存储键值和指针信息,假设每个磁盘块能存储4个键值及指针信息,则变成B+树后其结构如下图所示:
首先,B+树的查找和B树一样,起始于根节点,自顶向下遍历树。
不同的是,B+树中间节点不存储数据,只有键值和指针,而B树每个结点要存储键值和实际数据,这就意味着同样的大小的磁盘块B+树可以容纳更多节点元素,在相同的数据量下,B+树更加“矮胖”,IO操作更少 。
现代操作系统中,磁盘的存储结构使用的是B+树机制,MySQL的InnoDB引擎的存储方式也是B+树机制 。
命令:show engines \G;
mysql> show engines \G;
*************************** 1. row ***************************
Engine: InnoDB
Support: DEFAULT
Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES
XA: YES
Savepoints: YES
*************************** 2. row ***************************
Engine: MRG_MYISAM
Support: YES
Comment: Collection of identical MyISAM tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 3. row ***************************
Engine: MEMORY
Support: YES
Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 4. row ***************************
Engine: BLACKHOLE
Support: YES
Comment: /dev/null storage engine (anything you write to it disappears)
Transactions: NO
XA: NO
Savepoints: NO
*************************** 5. row ***************************
Engine: MyISAM
Support: YES
Comment: MyISAM storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 6. row ***************************
Engine: CSV
Support: YES
Comment: CSV storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 7. row ***************************
Engine: ARCHIVE
查看默认的存储引擎:show variables like ‘%storage_engine%’;
o 大于等于5.5之后,默认采用InnoDB引擎。
o InnoDB是MySQL的默认事务型引擎,它被设计用来处理大量的短期(short-lived)事务。可以确保事务的完整提交(Commit)和回滚(Rollback)。
o 除了增加和查询外,还需要更新,删除操作,那么,应优选选择InnoDB存储引擎。
o 除非有非常特别的原因需要使用其他的存储引擎,否则应该优先考虑InnoDB引擎。
o MyISAM提供了大量的特性,包括全文索引、压缩、空间函数(GIS)等,但MyISAM不支持事务和行级锁,有一个毫无疑问的缺陷就是崩溃后无法安全恢复。
o 5.5之前默认的存储引擎
o Archive档案存储引擎只支持INSERT和SELECT操作,在MySQL5.1之前不支持索引。
o Archive表**适合日志和数据采集(档案)**类应用。
o 根据英文的测试结论来看,Archive表比MyISAM表要小大约75%,比支持事务处理的InnoDB表小大约83%。
o Blackhole引擎没有实现任何存储机制,它会丢弃所有插入的数据,不做任何保存。
o 但服务器会记录Blackhole表的日志,所以可以用于复制数据到备库,或者简单地记录到日志。但这种应用方式会碰到很多问题,因此并不推荐。
o CSV引擎可以将普通的CSV文件作为MySQL的表来处理,但不支持索引。
o CSV引擎可以作为一种数据交换的机制,非常有用。
o CSV存储的数据直接可以在操作系统里,用文本编辑器,或者excel读取。
o 如果需要快速地访问数据,并且这些数据不会被修改,重启以后丢失也没有关系,那么使用Memory表是非常有用。
o Memory表至少比MyISAM表要快一个数量级。
o Federated引擎是访问其他MySQL服务器的一个代理,尽管该引擎看起来提供了一种很好的跨服务器的灵活性,但也经常带来问题,因此默认是禁用的。
对比项 | MyISAM | InnoDB |
---|---|---|
外键 | 不支持 | 支持 |
事务 | 不支持 | 支持 |
行表锁 | 表锁,即使操作一条记录也会锁住整个表,不适合高并发的操作 | 行锁,操作时只锁某一行,不对其它行有影响,适合高并发的操作 |
缓存 | 只缓存索引,不缓存真实数据 | 不仅缓存索引还要缓存真实数据,对内存要求较高,而且内存大小对性能有决定性的影响 |
自带系统表使用 | Y | N |
关注点 | 性能:节省资源、消耗少、简单业务 | 事务:并发写、事务、更大资源 |
默认安装 | Y | Y |
默认使用 | N | Y |
Percona 为 MySQL 数据库服务器进行了改进,在功能和性能上较 MySQL 有很显著的提升。
该版本提升了在高负载情况下的 InnoDB 的性能、为 DBA 提供一些非常有用的性能诊断工具;另外有更多的参数和命令来控制服务器行为。
该公司新建了一款存储引擎叫Xtradb完全可以替代Innodb,并且在性能和并发上做得更好,
阿里巴巴大部分mysql数据库其实使用的percona的原型加以修改。
AliSql+AliRedisL
数据过多——分库分表 mycat
索引失效,没有充分利用到索引——索引建立
关联查询太多join(设计缺陷或不得已的需求)——SQL优化
服务器调优及各个参数设置(缓冲、线程数等)——调整my.cnf
随着MySQL版本的更新换代,其优化器也在不断的升级,优化器会分析不同执行顺序产生的性能消耗不同而动态调整执行顺序。
下面是经常出现的查询顺序:
CREATE TABLE `t_dept` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`deptName` VARCHAR(30) DEFAULT NULL,
`address` VARCHAR(40) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `t_emp` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) DEFAULT NULL,
`age` INT(3) DEFAULT NULL,
`deptId` INT(11) DEFAULT NULL,
`empno` INT(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_dept_id` (`deptId`)
#CONSTRAINT `fk_dept_id` FOREIGN KEY (`deptId`) REFERENCES `t_dept` (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO t_dept(id,deptName,address) VALUES(1,'华山','华山');
INSERT INTO t_dept(id,deptName,address) VALUES(2,'丐帮','洛阳');
INSERT INTO t_dept(id,deptName,address) VALUES(3,'峨眉','峨眉山');
INSERT INTO t_dept(id,deptName,address) VALUES(4,'武当','武当山');
INSERT INTO t_dept(id,deptName,address) VALUES(5,'明教','光明顶');
INSERT INTO t_dept(id,deptName,address) VALUES(6,'少林','少林寺');
INSERT INTO t_emp(id,NAME,age,deptId,empno) VALUES(1,'风清扬',90,1,100001);
INSERT INTO t_emp(id,NAME,age,deptId,empno) VALUES(2,'岳不群',50,1,100002);
INSERT INTO t_emp(id,NAME,age,deptId,empno) VALUES(3,'令狐冲',24,1,100003);
INSERT INTO t_emp(id,NAME,age,deptId,empno) VALUES(4,'洪七公',70,2,100004);
INSERT INTO t_emp(id,NAME,age,deptId,empno) VALUES(5,'乔峰',35,2,100005);
INSERT INTO t_emp(id,NAME,age,deptId,empno) VALUES(6,'灭绝师太',70,3,100006);
INSERT INTO t_emp(id,NAME,age,deptId,empno) VALUES(7,'周芷若',20,3,100007);
INSERT INTO t_emp(id,NAME,age,deptId,empno) VALUES(8,'张三丰',100,4,100008);
INSERT INTO t_emp(id,NAME,age,deptId,empno) VALUES(9,'张无忌',25,5,100009);
INSERT INTO t_emp(id,NAME,age,deptId,empno) VALUES(10,'韦小宝',18,NULL,100010);
SELECT FROM t_emp a **INNER JOIN** t_dept b ON a.deptid = b.id ;
2. A、B两表共有+A的独有(列出所有用户,并显示其机构信息)A的全集
SELECT * FROM t_emp a **LEFT JOIN** t_dept b ON a.deptid = b.id ;
3. A、B两表共有+B的独有(列出所有部门,并显示其部门的员工信息 )B的全集
SELECT * FROM t_emp a **RIGHT JOIN** t_dept b ON a.deptid = b.id ;
SELECT * FROM t_emp a LEFT JOIN t_dept b ON a.deptid = b.id WHERE b.id IS NULL ;
SELECT * FROM t_emp a RIGHT JOIN t_dept b ON a.deptid = b.id WHERE a.id IS NULL ;
#MySQL Full Join的实现 因为MySQL不支持FULL JOIN,下面是替代方法
#left join + union(去重)+ right join
SELECT * FROM t_emp a LEFT JOIN t_dept b ON a.deptid = b.id
UNION
SELECT * FROM t_emp a RIGHT JOIN t_dept b ON a.deptid = b.id ;
SELECT * FROM t_emp a LEFT JOIN t_dept b ON a.deptid = b.id
UNION ALL
SELECT * FROM t_emp a RIGHT JOIN t_dept b ON a.deptid = b.id ;
1.UNION ALL 不会自动去重。
2.UNION在使用时,两张表的字段保证一致,如果不一致,请在slect后面列选字段,不要使用*
7 A的独有+B的独有(查询没有加入任何部门的员工,以及查询出部门下没有任何员工的部门)
SELECT * FROM t_emp a LEFT JOIN t_dept b ON a.deptid = b.id WHERE b.id IS NULL
UNION
SELECT * FROM t_emp a RIGHT JOIN t_dept b ON a.deptid = b.id WHERE a.id IS NULL ;
ALTER TABLE t_dept ADD CEO INT(11);
UPDATE t_dept SET CEO=2 WHERE id=1;
UPDATE t_dept SET CEO=4 WHERE id=2;
UPDATE t_dept SET CEO=6 WHERE id=3;
UPDATE t_dept SET CEO=8 WHERE id=4;
UPDATE t_dept SET CEO=9 WHERE id=5;
SELECT b.deptname,a.name FROM t_dept b LEFT JOIN t_emp a ON b.ceo = a.id ;
SELECT AVG(a.age) FROM t_emp a INNER JOIN t_dept b ON a.id = b.ceo ;
求所有人,对应的掌门是谁(课堂练习,4种写法分析)
#临时表连接方式
#step1根据ceo 去查找每个部门的掌门是谁
{SELECT b.id AS deptId,a.name AS ceoname FROM t_emp a INNER JOIN t_dept b ON a.id = b.ceo }
#step2 与员工表整合
SELECT c.name,ab.ceoname FROM t_emp c LEFT JOIN
( SELECT b.id AS deptId,a.name AS ceoname FROM t_emp a INNER JOIN t_dept b ON a.id = b.ceo ) ab
ON c.deptId = ab.deptId ;
#临时表连接方式 根据员工id查找
#step1 根据部门Id 查询员工的信息
SELECT a.name,b.ceo FROM t_emp a LEFT JOIN t_dept b ON a.deptid = b.id
# step2 与员工表整合
SELECT ab.name,c.name AS ceoname FROM
( SELECT a.name,b.ceo FROM t_emp a LEFT JOIN t_dept b ON a.deptid = b.id ) ab
LEFT JOIN t_emp c ON ab.ceo = c.id ;
#三表左连接方式
SELECT a.name,c.name AS ceoname FROM t_emp a
LEFT JOIN t_dept b ON a.deptid = b.id
LEFT JOIN t_emp c ON b.ceo = c.id ;
#子查询方式
SELECT a.name ,(SELECT c.name FROM t_emp c WHERE c.id=b.ceo) AS ceoname
FROM t_emp a LEFT JOIN t_dept b
ON a.deptid = b.id ;
#1、列出自己的掌门比自己年龄小的人员
#2、列出所有年龄低于自己门派平均年龄的人员
#3、列出至少有2个年龄大于40岁的成员的门派
#4、至少有2位非掌门人成员的门派
#5、列出全部人员,并增加一列备注“是否为掌门”,如果是掌门人显示是,不是掌门人显示否
#6、列出全部门派,并增加一列备注“老鸟or菜鸟”,若门派的平均值年龄>50显示“老鸟”,否则显示“菜鸟”
#7、显示每个门派年龄最大的人
#8、显示每个门派年龄第二大的人
索引的本质:索引是数据结构。你可以简单理解为“排好序的快速查找数据结构”。
(1) 详解(重要)
左边是数据表,一共有两列七条记录,最左边的是数据记录的物理地址
为了加快Col2的查找,可以维护一个右边所示的二叉查找树,每个节点分别包含索引键值和一个指向对应数据记录物理地址的指针,这样就可以运用二叉查找在一定的复杂度内获取到相应数据,从而快速的检索出符合条件的记录。
(2) 结论
数据本身之外,数据库还维护着一个满足特定查找算法的数据结构,这些数据结构以某种方式指向数据, 这样就可以在这些数据结构的基础上实现高级查找算法,这种数据结构就是索引。
磁盘块和磁盘页
类似大学图书馆建书目索引,提高数据检索的效率,降低数据库的IO成本
通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗
实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引列也是要占用空间的
虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。 因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段, 都会调整因为更新所带来的键值变化后的索引信息
聚簇索引并不是一种单独的索引类型,而是一种数据存储方式。
术语‘聚簇’表示数据跟索引放在一起就是聚簇索引。
如下图,左侧的索引就是聚簇索引,因为数据行在磁盘的排列和索引排序保持一致。
聚簇索引的好处:
按照聚簇索引排列顺序,查询显示一定范围数据的时候,由于数据都是紧密相连,数据库不用从多个数据块中提取数据,所以节省了大量的io操作。
聚簇索引的限制:
对于MySQL数据库目前只有innodb数据引擎支持聚簇索引,而Myisam并不支持聚簇索引。
由于数据物理存储排序方式只能有一种,所以每个MySQL的表只能有一个聚簇索引。一般情况下就是该表的主键。
为了充分利用聚簇索引的聚簇的特性,所以innodb表的主键列尽量选用有序的顺序id,而不建议用无序的id,比如uuid这种。
即一个索引只包含单个列,一个表可以有多个单列索引
语法:
随表一起建索引:
CREATE TABLE customer (
id INT(10) UNSIGNED AUTO_INCREMENT ,
customer_no VARCHAR(200),
customer_name VARCHAR(200),
PRIMARY KEY(id),
KEY (customer_name)
);
单独建单值索引:
CREATE INDEX idx_customer_name ON customer(customer_name);
删除索引:
DROP INDEX idx_customer_name on customer;
索引列的值必须唯一,但允许有空值
语法:
随表一起建索引:
CREATE TABLE customer (
id INT(10) UNSIGNED AUTO_INCREMENT ,
customer_no VARCHAR(200),
customer_name VARCHAR(200),
PRIMARY KEY(id),
KEY (customer_name),
UNIQUE (customer_no)
);
单独建唯一索引:
CREATE UNIQUE INDEX idx_customer_no ON customer(customer_no);
删除索引:
DROP INDEX idx_customer_no on customer ;
设定为主键后数据库会自动建立索引,innodb****为聚簇索引
语法:
随表一起建索引:
CREATE TABLE customer (
id INT(10) UNSIGNED AUTO_INCREMENT ,
customer_no VARCHAR(200),
customer_name VARCHAR(200),
PRIMARY KEY(id)
);
CREATE TABLE customer2 (
id INT(10) UNSIGNED ,
customer_no VARCHAR(200),
customer_name VARCHAR(200)
);
单独建主键索引:
ALTER TABLE customer2 add PRIMARY KEY customer2(id);
删除主键索引:
ALTER TABLE customer2 drop PRIMARY KEY ;
修改主键索引:
必须先删除掉(drop)原索引,再新建(add)索引
即一个索引包含多个列
语法:
随表一起建索引:
CREATE TABLE customer (
id INT(10) UNSIGNED AUTO_INCREMENT ,
customer_no VARCHAR(200),
customer_name VARCHAR(200),
PRIMARY KEY(id),
KEY (customer_name),
UNIQUE (customer_name),
KEY (customer_no,customer_name)
);
单独建索引:
CREATE INDEX idx_customer_no_name ON customer(customer_no,customer_name);
删除索引:
DROP INDEX idx_customer_no_name on customer ;
CREATE [UNIQUE ] INDEX indexName ON mytable(columnname(length));
如果是CHAR,VARCHAR类型,length可以小于字段实际长度; 如果是BLOB和TEXT类型,必须指定length。
ALTER mytable ADD [UNIQUE ] INDEX [indexName] ON (columnname(length))
DROP INDEX [indexName] ON mytable;
SHOW INDEX FROM table_name
有四种方式来添加数据表的索引:
ALTER TABLE tbl_name ADD PRIMARY KEY (column_list): 该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL。
ALTER TABLE tbl_name ADD UNIQUE index_name (column_list): 这条语句创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次)。
ALTER TABLE tbl_name ADD INDEX index_name (column_list): 添加普通索引,索引值可出现多次。
ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list):该语句指定了索引为 FULLTEXT ,用于全文索引。
主键自动建立唯一索引
频繁作为查询条件的字段应该创建索引
查询中与其它表关联的字段,外键关系建立索引
单键/组合索引的选择问题,who?(在高并发下倾向创建组合索引)
查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
查询中统计或者分组字段
思考:排序和分组哪个更伤性能?
300万数据时MySQL性能就开始下降了,这时就可以开始开始优化了
提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。
因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件
MySQL中有专门负责优化SELECT语句的优化器模块,主要功能:通过计算分析系统中收集到的统计信息,为客户端请求的Query提供他认为最优的执行计划(他认为最优的数据检索方式,但不见得是DBA认为是最优的,这部分最耗费时间)
当客户端向MySQL 请求一条Query,命令解析器模块完成请求分类,区别出是 SELECT 并转发给MySQL Query Optimizer时,MySQL Query Optimizer 首先会对整条Query进行优化,处理掉一些常量表达式的预算,直接换算成常量值。并对 Query 中的查询条件进行简化和转换,如去掉一些无用或显而易见的条件、结构调整等。然后分析 Query 中的 Hint 信息(如果有),看显示Hint信息是否可以完全确定该Query 的执行计划。如果没有 Hint 或Hint 信息还不足以完全确定执行计划,则会读取所涉及对象的统计信息,根据 Query 进行写相应的计算分析,然后再得出最后的执行计划。
使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是 如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈
官网介绍 https://dev.mysql.com/doc/refman/5.7/en/explain-output.html
表的读取顺序
数据读取操作的操作类型
哪些索引可以使用
哪些索引被实际使用
表之间的引用
每张表有多少行被优化器查询
EXPLAIN输出项(来源于mysql5.7文档)
Column | JSON Name | Meaning |
---|---|---|
id | select_id | The SELECT identifier |
select_type | None | The SELECT type |
table | table_name | The table for the output row |
partitions | partitions | The matching partitions |
type | access_type | The join type |
possible_keys | possible_keys | The possible indexes to choose |
key | key | The index actually chosen |
key_len | key_length | The length of the chosen key |
ref | ref | The columns compared to the index |
rows | rows | Estimate of rows to be examined |
filtered | filtered | Percentage of rows filtered by table condition |
Extra | None | Additional information |
CREATE TABLE t1(id INT(10) AUTO_INCREMENT,content VARCHAR(100) NULL , PRIMARY KEY (id));
CREATE TABLE t2(id INT(10) AUTO_INCREMENT,content VARCHAR(100) NULL , PRIMARY KEY (id));
CREATE TABLE t3(id INT(10) AUTO_INCREMENT,content VARCHAR(100) NULL , PRIMARY KEY (id));
CREATE TABLE t4(id INT(10) AUTO_INCREMENT,content VARCHAR(100) NULL , PRIMARY KEY (id));
INSERT INTO t1(content) VALUES(CONCAT('t1_',FLOOR(1+RAND()*1000)));
INSERT INTO t2(content) VALUES(CONCAT('t2_',FLOOR(1+RAND()*1000)));
INSERT INTO t3(content) VALUES(CONCAT('t3_',FLOOR(1+RAND()*1000)));
INSERT INTO t4(content) VALUES(CONCAT('t4_',FLOOR(1+RAND()*1000)));
select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
三种情况
1) id相同,执行顺序由上至下
select * from t1,t2,t3;
(2) id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
explain select t1.id from t1 where t1.id = (select t2.id from t2 where t2.id = (select t3.id from t3 where t3.content='t3_897'));
id相同,不同,同时存在;
id如果相同,可以认为是一组,从上往下顺序执行;
在所有组中,id值越大,优先级越高,越先执行;
关注点:id号每个号码,表示一趟独立的查询。一个sql的查询趟数越少越好。
(1)SIMPLE
EXPLAIN SELECT * FROM t1;
(2)PRIMARY
EXPLAIN select t1.id from t1 where t1.id = (select t2.id from t2 where t2.id = (select t3.id from t3 where t3.content=‘t3_897’));
(3) SUBQUERY
(4) DEPENDENT SUBQUERY
EXPLAIN SELECT * FROM t3 WHERE id = ( SELECT id FROM t2 WHERE content = t3.content);
(5) UNCACHEABLE SUBQUREY
EXPLAIN SELECT * FROM t3 WHERE id = ( SELECT id FROM t2 WHERE content = @@character_set_server);
(6) UNION
EXPLAIN SELECT * FROM (SELECT * FROM t1 UNION SELECT * FROM t2) aa;
(7) UNION RESULT
type显示的是访问类型,是较为重要的一个指标,结果值从最好到最坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
system>const>eq_ref>ref>range>index>ALL
一般来说,得保证查询至少达到range级别,最好能达到ref。
explain SELECT * from mysql.proxies_priv WHERE User
=‘root’;
explain select * from t1 where id = 1;
explain select * from t1,t2 where t1.id = t2.id;
create index idx_content on t1(content);
EXPLAIN SELECT * FROM t1, t2 WHERE t1.content = t2.content;
explain select * from t2 where id >1 and id <5;
explain select id from t1;
explain select * from t2;
EXPLAIN SELECT SQL_NO_CACHE * FROM t_emp WHERE t_emp.age=30 AND t_emp.name LIKE ‘ab%’;
第一组
key_len=age的字节长度+name的字节长度=(4+1) + ( 20*3+2+1) = 5+63 = 68
第二组
key_len=age的字节长度=4+1=5
key_len的长度计算公式:
varchr(10)变长字段且允许NULL = 10 * ( character set:utf8=3,gbk=2,latin1=1)+1(NULL)+2(变长字段)
varchr(10)变长字段且不允许NULL = 10 * ( character set:utf8=3,gbk=2,latin1=1)+2(变长字段)
char(10)固定字段且允许NULL = 10 * ( character set:utf8=3,gbk=2,latin1=1)+1(NULL)
char(10)固定字段且不允许NULL = 10 * ( character set:utf8=3,gbk=2,latin1=1)
显示将哪些列或常量与键列中命名的索引进行比较,以从表中选择行。
explain select * from t1,t2 where t1.id = t2.id;
表示使用了覆盖索引 [content是一个索引]
o 表明使用了where过滤!
如果有它则表明关联字段没有使用索引!
CREATE TABLE `dept` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`deptName` VARCHAR(30) DEFAULT NULL,
`address` VARCHAR(40) DEFAULT NULL,
`ceo` INT NULL ,
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `emp` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`empno` INT NOT NULL ,
`name` VARCHAR(20) DEFAULT NULL,
`age` INT(3) DEFAULT NULL,
`deptId` INT(11) DEFAULT NULL,
PRIMARY KEY (`id`)
#CONSTRAINT `fk_dept_id` FOREIGN KEY (`deptId`) REFERENCES `t_dept` (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
创建函数,假如报错:This function has none of DETERMINISTIC......
# 由于开启过慢查询日志bin-log, 我们就必须为我们的function指定一个参数。
#主从复制,主机会将写操作记录在bin-log日志中。从机读取bin-log日志,执行语句来同步数据。
#如果使用函数来操作数据,会导致从机和主键操作时间不一致。所以,默认情况下,mysql不开启创建函数设置
#查看mysql是否允许创建函数:
show variables like 'log_bin_trust_function_creators';
#命令开启:允许创建函数设置:
set global log_bin_trust_function_creators=1;
# 不加global只是当前窗口有效。mysqld重启,上述参数又会消失。
#永久方法:
• linux下:/etc/my.cnf下my.cnf[mysqld]加上:log_bin_trust_function_creators=1
随机产生字符串
DELIMITER $$
CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255)
BEGIN
DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
DECLARE return_str VARCHAR(255) DEFAULT '';
DECLARE i INT DEFAULT 0;
WHILE i < n DO
SET return_str =CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1));
SET i = i + 1;
END WHILE;
RETURN return_str;
END $$
#假如要删除
DELIMITER ;
drop function rand_string;
随机产生部门编号
#用于随机产生多少到多少的编号
DELIMITER $$
CREATE FUNCTION rand_num (from_num INT ,to_num INT) RETURNS INT(11)
BEGIN
DECLARE i INT DEFAULT 0;
SET i = FLOOR(from_num +RAND()*(to_num - from_num+1)) ;
RETURN i;
END$$
#假如要删除
DELIMITER ;
drop function rand_num;
创建往emp表中插入数据的存储过程
DELIMITER $$
CREATE PROCEDURE insert_emp( START INT , max_num INT )
BEGIN
DECLARE i INT DEFAULT 0;
SET autocommit = 0; #设置手动提交事务
REPEAT #循环
SET i = i + 1; #赋值
INSERT INTO emp (empno, NAME ,age ,deptid ) VALUES ((START+i),rand_string(6),rand_num(30,50),rand_num(1,10000));
UNTIL i = max_num
END REPEAT;
COMMIT; #提交事务
END$$
#删除
DELIMITER ;
drop PROCEDURE insert_emp;
创建往dept表中插入数据的存储过程
#执行存储过程,往dept表添加随机数据
DELIMITER $$
CREATE PROCEDURE `insert_dept`( max_num INT )
BEGIN
DECLARE i INT DEFAULT 0;
SET autocommit = 0;
REPEAT
SET i = i + 1;
INSERT INTO dept ( deptname,address,ceo ) VALUES (rand_string(8),rand_string(10),rand_num(1,500000));
UNTIL i = max_num
END REPEAT;
COMMIT;
END$$
#删除
DELIMITER ;
drop PROCEDURE insert_dept;
Dept
执行存储过程,往dept表添加1万条数据
CALL insert_dept(10000);
执行存储过程,往emp表添加50万条数据
CALL insert_emp(100000,500000);
SHOW INDEX FROM t_emp ; 只能查看索引,但不能删除。
Drop index idx_name on table_name;
存储索引的表(元数据库,统计表),我们可以对表数据进行删除操作。
DROP INDEX idx_xxx ON emp
SHOW INDEX FROM t_emp
元数据:meta DATA 描述数据的数据
SELECT index_name FROM information_schema.STATISTICS WHERE table_name=‘t_emp’ AND table_schema=‘mydb’;
AND index_name <>‘PRIMARY’ AND seq_in_index = 1
CURSOR 游标
FETCH xxx INTO xxx
PREPARE XXX 预编译语句
EXECUTE
CALL proc_drop_index (‘mydb’,‘t_emp’);
删除表上所有索引
DELIMITER $$
CREATE PROCEDURE `proc_drop_index`(dbname VARCHAR(200),tablename VARCHAR(200))
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE ct INT DEFAULT 0;
DECLARE _index VARCHAR(200) DEFAULT '';
DECLARE _cur CURSOR FOR SELECT index_name FROM information_schema.STATISTICS WHERE table_schema=dbname AND table_name=tablename AND seq_in_index=1 AND index_name <>'PRIMARY' ;
#每个游标必须使用不同的declare continue handler for not found set done=1来控制游标的结束
DECLARE CONTINUE HANDLER FOR NOT FOUND set done=2 ;
#若没有数据返回,程序继续,并将变量done设为2
OPEN _cur;
FETCH _cur INTO _index;
WHILE _index<>'' DO
SET @str = CONCAT("drop index " , _index , " on " , tablename );
PREPARE sql_str FROM @str ;
EXECUTE sql_str;
DEALLOCATE PREPARE sql_str;
SET _index='';
FETCH _cur INTO _index;
END WHILE;
CLOSE _cur;
END$$
CALL proc_drop_index(“mydb”,“emp”);
CALL proc_drop_index(“mydb”,“dept”);
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid=4 AND emp.name = 'abcd';
CREATE INDEX idx_age ON emp(age);
CREATE INDEX idx_age_deptid ON emp(age,deptid);
CREATE INDEX idx_age_deptid_name ON emp(age,deptid,NAME);
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 AND emp.name = 'abcd' ;
或者
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.deptid=1 AND emp.name = 'abcd';
那原来的idx_age_deptid_name 还能否正常使用?不能
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE deptid=4 AND emp.age=30 AND emp.name = ‘abcd’; #
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 AND emp.name = ‘abcd’ ; # 部分被使用
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.deptid=1 AND emp.name = ‘abcd’; # 完全没有
结论:过滤条件要使用索引必须按照索引建立时的顺序,依次满足,一旦跳过某个字段,索引后面的字段都无法被使用。
如果where 条件后面索引都存在的情况下,mysql 的优化器会自动使用索引
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.name LIKE ‘abc%’;
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE LEFT(emp.name,3) = ‘abc’;
CREATE INDEX idx_name ON emp(NAME);
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 AND emp.deptId>20 AND emp.name = ‘abc’ ;
不能,范围右边的列不能使用。
如果这种sql 出现较多,应该建立:
create index idx_age_name_deptid on emp(age,name,deptid);
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 AND emp.name = ‘abc’ AND emp.deptId>20 ;
CREATE INDEX idx_name ON emp(NAME);
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.name <> ‘abc’ ;
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.name != ‘abc’;
下列哪个sql语句可以用到索引
CREATE INDEX idx_age ON emp(age);
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE age IS NULL;
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE age IS NOT NULL;
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE name LIKE ‘ab%’;
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE name LIKE ‘**%**ab%’;
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE name=123;
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE name=‘123’;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ElvECeq1-1660200356803)(https://gitee.com/w0131/java/raw/master/img/202208111438166.jpg)]
name=123发生类型转换,索引失效。
设计实体类属性时,一定要与数据库字段类型相对应,否则会出现类型转换的情况。
假设index(a,b,c)
Where语句 | 索引是否被使用 |
---|---|
where a = 3 | Y,使用到a |
where a = 3 and b = 5 | Y,使用到a,b |
where a = 3 and b = 5 and c = 4 | Y,使用到a,b,c |
where b = 3 或者 where b = 3 and c = 4 或者 where c = 4 | N |
where a = 3 and c = 5 | 使用到a, 但是c不可以,b中间断了 |
where a = 3 and b > 4 and c = 5 | 使用到a和b, c不能用在范围之后,b断了 |
where a is null and b is not null | is null 支持索引 但是is not null 不支持,所以 a 可以使用索引,但是 b不可以使用 |
where a <> 3 | 不能使用索引 |
where abs(a) =3 | 不能使用 索引 |
where a = 3 and b like ‘kk%’ and c = 4 | Y,使用到a,b,c |
where a = 3 and b like ‘%kk’ and c = 4 | Y,只用到a |
where a = 3 and b like ‘%kk%’ and c = 4 | Y,只用到a |
where a = 3 and b like ‘k%kk%’ and c = 4 | Y,使用到a,b,c |
对于单键索引,尽量选择过滤性更好的索引(例如:手机号,邮件,身份证)
在选择组合索引的时候,过滤性最好的字段在索引字段顺序中,位置越靠前越好。
选择组合索引时,尽量包含where中更多字段的索引
组合索引出现范围查询时,尽量把这个字段放在索引次序的最后面
尽量避免造成索引失效的情况
#分类
CREATE TABLE IF NOT EXISTS `class` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`card` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`id`)
);
#图书
CREATE TABLE IF NOT EXISTS `book` (
`bookid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`card` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`bookid`)
);
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
下面开始explain分析
EXPLAIN SELECT SQL_NO_CACHE * FROM class LEFT JOIN book ON class.card = book.card;
结论:type 有All
CREATE INDEX idx_book_card ON book(card);
【右表被驱动表】,可以避免全表扫描
CREATE INDEX idx_class_card ON class(card);
#【左表驱动表】,无法避免全表扫描
换成inner join(MySQL自动选择驱动表)
先删除之前建立的索引!class book;
EXPLAIN SELECT SQL_NO_CACHE * FROM class INNER JOIN book ON class.card=book.card;
CREATE INDEX idx_class_card ON class(card);
保证被驱动表的join字段被索引
left join 时,选择小表作为驱动表,大表作为被驱动表
inner join 时,mysql会自动将小结果集的表选为驱动表。选择相信mysql优化策略。
能够直接多表关联的尽量直接关联,不用子查询
证明:
两种:非掌门人员
先创建一个索引
CREATE INDEX idx_ceo ON t_dept (ceo);
#①不推荐
Explain SELECT * FROM t_emp a WHERE a.id NOT IN
(SELECT b.ceo FROM t_dept b WHERE b.ceo IS NOT NULL);
#②推荐
Explain SELECT a.* FROM t_emp a
LEFT JOIN t_dept b
ON a.id = b.ceo
WHERE b.id IS NULL;
结论:
NOT IN -->LEFT JOIN xxx ON xx WHERE xx IS NULL
尽量不要使用not in 或者 not exists
CALL proc_drop_index(“mydb”,“emp”);
CALL proc_drop_index(“mydb”,“dept”);
以下是否能使用到索引,能否去掉using filesort
EXPLAIN SELECT SQL_NO_CACHE * FROM emp ORDER BY age,deptid;
EXPLAIN SELECT SQL_NO_CACHE * FROM emp ORDER BY age,deptid LIMIT 10;
创建索引
CREATE INDEX idx_age_deptid_name ON emp (age,deptid,NAME);
增加limit过滤条件,使用上索引了。
EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY deptid;
EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY deptid,NAME;
EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY deptid,empno;
EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY NAME,deptid;
EXPLAIN SELECT * FROM emp WHERE deptid=45 ORDER BY age;
CREATE INDEX idx_age_deptid_name ON emp (age,deptid,NAME)
CREATE INDEX idx_age_deptid_empno ON emp (age,deptid,empno);
EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY deptid DESC, NAME DESC ;
EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY deptid ASC, NAME DESC ;
执行案例前先清除emp上的索引,只留主键
CALL proc_drop_index(“mydb”,“emp”);
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE age =30 AND empno <101000 ORDER BY NAME ;
结论:很显然,type 是 ALL,即最坏的情况。Extra 里还出现了 Using filesort,也是最坏的情况。优化是必须的。
开始优化:思路: 尽量让where的过滤条件和排序使用上索引
CREATE INDEX idx_age_empno_name ON emp (age,empno,NAME);
我们发现using filesort 依然存在,所以name 并没有用到索引。
原因是,因为empno是一个范围过滤,所以索引后面的字段不会再使用索引了。
所以我们建一个3值索引是没有意义的
那么我们先删掉这个索引:DROP INDEX idx_age_empno_name ON emp;
CREATE INDEX idx_age_name ON emp(age,NAME);
也就是说empno 和name这个两个字段我只能二选其一。
这样我们优化掉了 using filesort。性能提升了。
DROP INDEX idx_age_name ON emp;
CREATE INDEX idx_age_empno ON emp(age,empno);
果然出现了filesort,而且type还是range光看字面其实并不美好。
结果竟然有 filesort的 sql 运行速度,超过了已经优化掉 filesort的 sql,而且快了好多倍。何故?
所有的排序都是在条件过滤之后才执行的,所以,如果条件过滤掉大部分数据的话,剩下几百几千条数据进行排序其实并不是很消耗性能,即使索引优化了排序,但实际提升性能很有限。
相对的 empno<101000 这个条件,如果没有用到索引的话,要对几万条的数据进行扫描,这是非常消耗性能的,所以索引放在这个字段上性价比最高,是最优选择。
当【范围条件】和【group by 或者 order by】的字段出现二选一时,优先观察条件字段的过滤数量,如果过滤的数据足够多,而需要排序的数据并不多时,优先把索引放在范围字段上。反之,亦然。
如果不在索引列上,filesort有两种算法: mysql就要启动双路排序和单路排序
MySQL 4.1之前是使用双路排序,字面意思就是两次扫描磁盘,最终得到数据, 读取行指针和order by列,对他们进行排序,然后扫描已经排序好的列表,按照列表中的值重新从列表中读取对应的数据输出
从磁盘取排序字段,在buffer进行排序,再从磁盘取其他字段。
取一批数据,要对磁盘进行两次扫描,众所周知,I\O是很耗时的,所以在mysql4.1之后,出现了第二种改进的算法,就是单路排序。
从磁盘读取查询需要的所有列,按照order by列在buffer对它们进行排序,然后扫描排序后的列表进行输出, 它的效率更快一些,避免了第二次读取数据。并且把随机IO变成了顺序IO,但是它会使用更多的空间, 因为它把每一行都保存在内存中了。
在sort_buffer中,单路比多路要多占用很多空间,因为单路是把所有字段都取出, 所以有可能取出的数据的总大小超出了sort_buffer的容量,导致每次只能取sort_buffer容量大小的数据,进行排序(创建tmp文件,多路合并),排完再取sort_buffer容量大小,再排……从而多次I/O。
单路本来想省一次I/O操作,反而导致了大量的I/O操作,反而得不偿失。
增大sort_buffer_size参数的设置
增大max_length_for_sort_data参数的设置
减少select 后面的查询的字段。 禁止使用select *
当Query的字段大小总和小于max_length_for_sort_data 而且排序字段不是 TEXT|BLOB 类型时,会用改进后的算法——单路排序, 否则用老算法——多路排序。
两种算法的数据都有可能超出sort_buffer的容量,超出之后,会创建tmp文件进行合并排序,导致多次I/O,但是用单路排序算法的风险会更大一些,所以要提高sort_buffer_size。
SHOW VARIABLES LIKE ‘%sort_buffer_size%’;
SHOW VARIABLES LIKE ‘%max_length_for_sort_data%’; #默认1024字节
group by 使用索引的原则几乎跟order by一致 ,唯一区别:
group by 先排序再分组,遵照索引建的最佳左前缀法则
当无法使用索引列,增大max_length_for_sort_data和sort_buffer_size参数的设置
where高于having,能写在where限定的条件就不要写在having中了
group by没有过滤条件,也可以用上索引。Order By 必须有过滤条件才能使用上索引。
简单说就是,select 到 from 之间查询的列使用了索引!
select * from tName 不建议使用*
未使用覆盖索引之前:
select sql_no_cache * from emp where name like ‘%abc’;
使用覆盖索引后
create index idx_age_deptid_name on emp(age,deptid,name);
explain select sql_no_cache id,age,deptid from emp where name like ‘%abc’;
禁止使用select *
禁止查询与业务无关字段
尽量使用覆盖索引
MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中。
long_query_time的默认值为10,意思是运行10秒以上的语句。
由他来查看哪些SQL超出了我们的最大忍耐时间值,比如一条sql执行超过5秒钟,我们就算慢SQL,希望能收集超过5秒的sql,结合之前explain进行全面分析。
默认情况下,MySQL数据库没有开启慢查询日志,需要我们手动来设置这个参数。
当然,如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会或多或少带来一定的性能影响。慢查询日志支持将日志记录写入文件。
SHOW VARIABLES LIKE ‘%slow_query_log%’;
默认情况下slow_query_log的值为OFF,表示慢查询日志是禁用的,
SHOW VARIABLES LIKE ‘%long_query_time%’;
SHOW GLOBAL VARIABLES LIKE ‘long_query_time’;
SET GLOBAL long_query_time=0.1;
SET SESSION long_query_time=0.1; #session可省略
假如运行时间正好等于long_query_time的情况,并不会被记录下来。也就是说,
在mysql源码里是判断大于long_query_time,而非大于等于。
永久生效
slow_query_log =1
slow_query_log_file=/var/lib/mysql/localhost-slow.log
long_query_time=3
log_output=FILE
SELECT * FROM emp;
SELECT * FROM emp WHERE deptid > 1;
/var/lib/mysql/localhost-slow.log
SHOW GLOBAL STATUS LIKE ‘%Slow_queries%’;
在生产环境中,如果要手工分析日志,查找、分析SQL,显然是个体力活,MySQL提供了日志分析工具mysqldumpslow。
查看mysqldumpslow的帮助信息
a) mysqldumpslow --help
-a: 不将数字抽象成N,字符串抽象成S
-s: 是表示按照何种方式排序;
c: 访问次数
l: 锁定时间
r: 返回记录
t: 查询时间
al:平均锁定时间
ar:平均返回记录数
at:平均查询时间
-t: 即为返回前面多少条的数据;
-g: 后边搭配一个正则匹配模式,大小写不敏感的;
得到返回记录集最多的10个SQL
mysqldumpslow -s r -t 10 /var/lib/mysql/localhost-slow.log
得到访问次数最多的10个SQL
mysqldumpslow -s c -t 10 /var/lib/mysql/localhost-slow.log
得到按照时间排序的前10条里面含有左连接的查询语句
mysqldumpslow -s t -t 10 -g "left join" /var/lib/mysql/localhost-slow.log
另外建议在使用这些命令时结合 | 和more 使用 ,否则有可能出现爆屏情况
mysqldumpslow -s r -t 10 /var/lib/mysql/localhost-slow.log | more
将一段查询sql封装为一个虚拟的表。
这个虚拟表只保存了sql逻辑,不会保存任何查询结果。
封装复杂sql语句,提高复用性
逻辑放在数据库上面,更新不需要发布程序,面对频繁的需求变更更灵活
共用查询结果
报表
创建
CREATE VIEW view_name AS SELECT column_name(s) FROM table_name WHERE condition
使用
查询
select * from view_name
更新
CREATE OR REPLACE VIEW view_name
AS SELECT column_name(s) FROM table_name WHERE condition
删除
drop view view_name;
CREATE VIEW v_ceo AS
SELECT emp.name, ceo.name AS ceoname
FROM t_emp emp
LEFT JOIN t_dept dept ON emp.deptid = dept.id
LEFT JOIN t_emp ceo ON dept.ceo = ceo.id;
INSERT INTO t_emp (NAME,age,deptId,empno) VALUES ('岳灵珊',18,1,100011);
总结:mysql 视图会随着表中的数据变化而动态变化!
slave会从master读取binlog来进行数据同步
三步骤+原理图
MySQL复制三步骤: 1 master将写操作记录到二进制日志(binary log)。这些记录过程叫做二进制日志事件,binary log events; 2 slave将master的binary log events拷贝到它的中继日志(relay log); 从服务器I/O线程将主服务器的二进制日志读取过来记录到从服务器本地文件,然后SQL线程会读取relay-log日志的内容并应用到从服务器,从而使从服务器和主服务器的数据保持一致! 3 slave重做中继日志中的事件,将改变应用到自己的数据库中。 MySQL复制是异步的且串行化的,而且重启后从接入点开始复制。 * 复制的最大问题(延时)
每个slave只有一个master
每个slave只能有一个唯一的服务器ID
每个master可以有多个salve
logbin格式:
binlog_format=STATEMENT(默认):数据操作的时间,同步时不一致
binlog_format=ROW:批量数据操作时,效率低
binlog_format=MIXED:是以上两种level的混合使用,有函数用ROW,没函数用STATEMENT,但是无法识别系统变量
server-id=1
log-bin=mysql-bin
binlog-ignore-db=mysql
binlog-ignore-db=infomation_schema
binlog-do-db=mytestdb
binlog_format=STATEMENT
先不要创建mytestdb数据库。主从搭建好了再创建。
主从所有配置项都配置在[mysqld]节点下,且都是小写字母
[必须]从服务器唯一ID:server-id=2
[可选]启用中继日志:relay-log=mysql-relay
server-id=2
relay-log=mysql-relay
systemctl restart mysqld
GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%' IDENTIFIED BY '123456';
flush privileges;
grant all privileges on . to root@‘%’ identified by ‘root’;
flush privileges;
给root 用户授予远程访问权限
查询master的状态: show master status;
记下File和Position的值
执行完此步骤后不要再操作主服务器MYSQL,防止主服务器状态值变化
CHANGE MASTER TO MASTER_HOST=‘主机ip地址’,
MASTER_USER=‘X’,MASTER_PASSWORD=‘X’,
MASTER_LOG_FILE=‘mysql-bin.具体数字’,MASTER_LOG_POS=具体值;
start slave;
show slave status\G;
下面两个参数都是Yes,则说明主从配置成功!
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
**如果出现:**Slave_IO_Running:No
则可能的解决办法是:
1)停止stop slave; 再启动start slave;看是否能正常运行
2)两个服务器的防火墙是否关闭,是否互相能ping通
3)配置文件是否正确、是否重启了服务器
4)连接主机的语句是否正确
5)可能是uuid 一致(master,slave uuid) vim /var/lib/mysql/auto.cnf 下更改uuid,重启服务
CREATE DATABASE mytestdb;
CREATE TABLE mytbl(id INT,NAME VARCHAR(16));
INSERT INTO mytbl VALUES(1, ‘zhang3’);
INSERT INTO mytbl VALUES(2, ‘li4’);
在从机上执行。功能说明:停止I/O 线程和SQL线程的操作。
mysql> stop slave;
在从机上执行。功能说明:用于删除SLAVE数据库的relaylog日志文件,并重新启用新的relaylog文件。
mysql> reset slave;
在主机上执行。功能说明:删除所有的binglog日志文件,并将日志索引文件清空,重新开始所有新的日志文件。
用于第一次进行搭建主从库时,进行主库binlog初始化工作;
mysql> reset master;