详细安装参考文章
mysql -u root -p
:运行mysql;默认为mysql -h 127.0.0.1 -p 3306 -u root -p
mysql --version
:查看mysql版本
select version();
:查看mysql版本
show databases;
:查看数据库
use 库名;
:打开指定的库
show tables;
:查看当前库的所有表
show tables from 库名;
:查看其他库的所有表
create database 库名;
:创建库
create table 表名(列名 列类型,列名 列类型,...);
:创建表
desc 表名;
:查看表结构
没改字符集之前,我们使用insert 插入带中文的数据,会插入失败
使用vim /etc/my.cnf
命令进入配置文件,本mysql版本为5.7,每个版本配置文件可能有所不同
[mysqld]
#加入编码
character_set_server=utf8
init_connect='SET NAMES utf8'
保存并退出,systemctl restart mysqld
重启服务,如果起的来,说明配置文件没有出错
再次进入数据库,插入中文发现还是插入失败或者乱码,原因:应该重新创建数据库建表插入
插入成功
二进制日志文件 log-bin
错误日志log-error
查询日志 log
数据文件
Management Serveices & Utilities | 系统管理和控制工具 |
---|---|
SQL Interface | SQL 接口。 接受用户的 SQL 命令, 并且返回用户需要查询的结果。 比如 select from 就是调用 SQL Interface |
Parser | 解析器。 SQL 命令传递到解析器的时候会被解析器验证和解析 |
Optimizer | 查询优化器。 SQL 语句在查询之前会使用查询优化器对查询进行优化, 比如有 where 条件时, 优化器来决定先投影还是先过滤。 |
Cache 和 Buffer | 查询缓存。 如果查询缓存有命中的查询结果, 查询语句就可以直接去查询缓存中取 数据。 这个缓存机制是由一系列小缓存组成的。 比如表缓存, 记录缓存, key 缓存, 权限缓存等 |
mysql的查询流程大致如下:
show engines;
:查看mysql支持的储存引擎[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cmYNztxg-1617521137613)(D:\笔记\MySQL\img\Snipaste_2021-03-31_11-09-54.png)]
show variables like '%storage_engine%';
:查看mysql默认的存储引擎对比项 | MyISAM | InnoDB |
---|---|---|
主外键 | 不支持 | 支持 |
事务 | 不支持 | 支持 |
行表锁 | 表锁,即使操作一条记录也会锁住整个表,不适合高并发的操作 | 行锁,操作时只锁某一行,不对其他行有影响(适合高并发的操作) |
缓存 | 只缓存索引,不缓存真实数据 | 不仅缓存索引还要缓存真实数据,对内存要求较高,而且内存大小对性能有决定性的影响 |
表空间 | 小 | 大 |
关注点 | 性能 | 事务 |
默认安装 | Y | Y |
性能下降、SQL 慢、执行时间长、等待时间长的原因分析:
create index idx_user_name on user(name)
create index idx_user_nameEmail on user(name,email)
手写顺序:
SELECT DISIINCT
<select_list>
FROM
<left_table> <join_type>
JOIN <right_table> ON <join_condition>
WHERE
<where_condition>
GROUP BY
<group_by_list>
HAVING
<having_condition>
ORDER BY
<order_by_condition>
LIMIT <limit_number>
mysql 机器执行sql顺序
FROM
<left_table> <join_type>
JOIN <right_table> ON <join_condition>
WHERE
<where_condition>
GROUP BY
<group_by_list>
HAVING
<having_condition>
SELECT DISIINCT
<select_list>
ORDER BY
<order_by_condition>
LIMIT <limit_number>
mysql 是从 FROM 开始执行
CREATE TABLE tbl_dept(
id INT(11) NOT NULL AUTO_INCREMENT,
deptName VARCHAR(30) DEFAULT NULL,
locAdd VARCHAR(40) DEFAULT NULL,
PRIMARY KEY(id)
)ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE tbl_emp (
id INT(11) NOT NULL AUTO_INCREMENT,
NAME VARCHAR(20) DEFAULT NULL,
deptId INT(11) DEFAULT NULL,
PRIMARY KEY (id),
KEY fk_dept_Id (deptId)
#CONSTRAINT 'fk_dept_Id' foreign key ('deptId') references 'tbl_dept'('Id')
)ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO tbl_dept(deptName,locAdd) VALUES('RD',11);
INSERT INTO tbl_dept(deptName,locAdd) VALUES('HR',12);
INSERT INTO tbl_dept(deptName,locAdd) VALUES('MK',13);
INSERT INTO tbl_dept(deptName,locAdd) VALUES('MIS',14);
INSERT INTO tbl_dept(deptName,locAdd) VALUES('FD',15);
INSERT INTO tbl_emp(NAME,deptId) VALUES('z3',1);
INSERT INTO tbl_emp(NAME,deptId) VALUES('z4',1);
INSERT INTO tbl_emp(NAME,deptId) VALUES('z5',1);
INSERT INTO tbl_emp(NAME,deptId) VALUES('w5',2);
INSERT INTO tbl_emp(NAME,deptId) VALUES('w6',2);
INSERT INTO tbl_emp(NAME,deptId) VALUES('s7',3);
INSERT INTO tbl_emp(NAME,deptId) VALUES('s8',4);
INSERT INTO tbl_emp(NAME,deptId) VALUES('s9',51);
select * from tbl_emp, tbl_dept;
select * from tbl_emp e inner join tbl_dept d on e.deptId = d.id;
tbl_emp 与 tbl_dept 的公共部分 + tbl_emp 表的独有部分
left join:取左表独有部分 + 两表公共部分
select * from tbl_emp e left join tbl_dept d on e.deptId = d.id;
select * from tbl_emp e right join tbl_dept d on e.deptId = d.id;
select * from tbl_emp e left join tbl_dept d on e.deptId = d.id where d.id is null;
select * from tbl_emp e right join tbl_dept d on e.deptId = d.id where e.id is null;
select * from tbl_emp e left join tbl_dept d on e.deptId = d.id union select * from tbl_emp e right join tbl_dept d on e.deptId = d.id;
select * from tbl_emp e left join tbl_dept d on e.deptId=d.id where d.id is null union select * from tbl_emp e right join tbl_dept d on e.deptId=d.id where e.deptId is null
优势:
劣势:
创建索引:
CREATE [UNIQUE] INDEX indexName ON mytable(columnname(length));
#或
ALTER TABLE mytable ADD [UNIQUE] INDEX [indexName] ON(columnname(length));
删除索引:
DROP INDEX [indexName] ON mytable;
查看索引:
SHOW INDEX FROM table_name\G # \G表示将查询到的横向表格纵向输出,方便阅读
使用 ALTER 命令,有四种方式来添加数据表的索引:
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,用于全文索引。哪些情况下合适建立索引:
哪些情况下不要创建索引:
因此应该只为经常查询和经常排序的数据列建立索引。注意,如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果。
MySQL Query Optimizer 的作用
MySQL 常见瓶颈
是什么?Explain 是查看执行计划
能干什么?
怎么用?
select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
id 取值的三种情况:
查询的类型,主要用于区别普通查询、联合查询、子查询等复杂查询
显示这一行数据是关于哪张表的
访问类型排列,显示查询使用了何种类型,type显示的是访问类型,是较为重要的一个指标,结果值从最好到最坏依次是:system>const>eq_ref>ref>fultext>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>ALL
常见的访问类型system>const>eq_ref>ref>range>index>ALL,一般来说,得保证查询至少达到range级别,最好能达到ref
从最好到最差依次是:system>const>eq_ref>ref>range>index>ALL
between
、<
、>
、in
等的查询这种范围扫描索引扫描比全表扫描要好,因为他只需要开始索引的某一点,而结束于另一点,不用扫描全部索引一般来说,得保证查询只是达到range级别,最好达到ref
显示可能应用在这张表中的索引,一个或多个
若查询涉及的字段上存在索引,则该索引将被列出,但不一定被查询实际使用
实际使用的索引,如果为null,则没有使用索引
若查询中使用了覆盖索引,则该索引仅出现在key列表中
根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数
包含不适合在其他列中显示但十分重要的额外信息
select *
,因为如果将所有字段一起做索引会导致索引文件过大,查询性能下降。COUNT(*)
操作,不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化。创建表
CREATE TABLE IF NOT EXISTS article(
id INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
author_id INT(10) UNSIGNED NOT NULL,
category_id INT(10) UNSIGNED NOT NULL,
views INT(10) UNSIGNED NOT NULL,
comments INT(10) UNSIGNED NOT NULL,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL
);
INSERT INTO article(author_id,category_id,views,comments,title,content)
VALUES
(1,1,1,1,'1','1'),
(2,2,2,2,'2','2'),
(1,1,3,3,'3','3');
查询案例
#根据案例写出SQL语句
select article_id from article where category_id=1 and comments>1 order by views desc limit 1;
#查询结果
+----+-----------+
| id | author_id |
+----+-----------+
| 3 | 1 |
+----+-----------+
1 row in set (0.00 sec)
SHOW INDEX FROM article;
查看表索引,由于刚刚建的表,只有一个默认主键索引
使用 explain 分析 SQL 语句的执行效率:EXPLAIN SELECT id, author_id FROM article WHERE category_id = 1 AND comments > 1 ORDER BY views DESC LIMIT 1;
创建索引
ALTER TABLE article ADD INDEX idx_article_ccv(`category_id`, `comments`, `views`);
#方法二
CREATE INDEX idx_article_ccv ON article(`category_id`, `comments`, `views`);
SHOW INDEX FROM article;
查看表索引comments > 1
改为 comments = 1
,发现 Use filesort 神奇地消失了,从这点可以验证:范围后的索引会导致索引失效删除索引
DROP INDEX idx_article_ccv ON article;
再次创建索引
create index idx_article_ccv on article(category_id, views);
由于 range 后(comments > 1
)的索引会失效,这次我们建立索引时,直接抛弃 comments 列,先利用 category_id 和 views 的联合索引查询所需要的数据,再从其中取出 comments > 1
的数据(我觉着应该是这样的)
次执行查询:可以看到,type变为了ref,Extra中的Using filesort也消失了,结果非常理想
两表索引优化分析:主外键
创建表
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 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)));
mysql> select * from class;
+----+------+
| id | card |
+----+------+
| 1 | 12 |
| 2 | 13 |
| 3 | 12 |
| 4 | 17 |
| 5 | 11 |
| 6 | 3 |
| 7 | 1 |
| 8 | 16 |
| 9 | 17 |
| 10 | 16 |
| 11 | 9 |
| 12 | 17 |
| 13 | 18 |
| 14 | 16 |
| 15 | 7 |
| 16 | 8 |
| 17 | 19 |
| 18 | 9 |
| 19 | 6 |
| 20 | 5 |
| 21 | 6 |
+----+------+
21 rows in set (0.00 sec)
mysql> select * from book;
+--------+------+
| bookid | card |
+--------+------+
| 1 | 16 |
| 2 | 1 |
| 3 | 17 |
| 4 | 3 |
| 5 | 20 |
| 6 | 12 |
| 7 | 18 |
| 8 | 13 |
| 9 | 13 |
| 10 | 4 |
| 11 | 1 |
| 12 | 13 |
| 13 | 20 |
| 14 | 20 |
| 15 | 1 |
| 16 | 2 |
| 17 | 9 |
| 18 | 16 |
| 19 | 14 |
| 20 | 2 |
+--------+------+
20 rows in set (0.00 sec)
查询案例
SELECT * FROM class LEFT JOIN book ON class.card = book.card;
EXPLAIN SELECT * FROM class LEFT JOIN book ON class.card = book.card;
添加索引:在右表添加索引
ALTER TABLE 'book' ADD INDEX Y ('card');
SHOW INDEX FROM book; #查看book表的索引
分析:
添加索引:在右表添加索引
DROP INDEX Y ON book;
ALTER TABLE class ADD INDEX X(card);
创建表
CREATE TABLE IF NOT EXISTS phone(
phoneid INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
card INT(10) UNSIGNED NOT NULL,
PRIMARY KEY(phoneid)
)ENGINE=INNODB;
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
mysql> select * from phone;
+---------+------+
| phoneid | card |
+---------+------+
| 1 | 3 |
| 2 | 9 |
| 3 | 14 |
| 4 | 2 |
| 5 | 9 |
| 6 | 19 |
| 7 | 8 |
| 8 | 1 |
| 9 | 3 |
| 10 | 9 |
| 11 | 17 |
| 12 | 18 |
| 13 | 19 |
| 14 | 18 |
| 15 | 14 |
| 16 | 16 |
| 17 | 17 |
| 18 | 19 |
| 19 | 20 |
| 20 | 3 |
+---------+------+
20 rows in set (0.00 sec)
查询案例
mysql> select * from class left join book on class.card=book.card left join phone on book.card=phone.card;
+----+------+--------+------+---------+------+
| id | card | bookid | card | phoneid | card |
+----+------+--------+------+---------+------+
| 14 | 9 | 8 | 9 | 2 | 9 |
| 16 | 9 | 8 | 9 | 2 | 9 |
| 18 | 9 | 8 | 9 | 2 | 9 |
| 3 | 14 | 7 | 14 | 3 | 14 |
| 19 | 14 | 7 | 14 | 3 | 14 |
| 3 | 14 | 11 | 14 | 3 | 14 |
| 19 | 14 | 11 | 14 | 3 | 14 |
| 14 | 9 | 8 | 9 | 5 | 9 |
| 16 | 9 | 8 | 9 | 5 | 9 |
| 18 | 9 | 8 | 9 | 5 | 9 |
| 1 | 19 | 6 | 19 | 6 | 19 |
| 4 | 19 | 6 | 19 | 6 | 19 |
| 8 | 8 | 20 | 8 | 7 | 8 |
| 9 | 8 | 20 | 8 | 7 | 8 |
| 11 | 1 | 5 | 1 | 8 | 1 |
| 20 | 1 | 5 | 1 | 8 | 1 |
| 14 | 9 | 8 | 9 | 10 | 9 |
| 16 | 9 | 8 | 9 | 10 | 9 |
| 18 | 9 | 8 | 9 | 10 | 9 |
| 1 | 19 | 6 | 19 | 13 | 19 |
| 4 | 19 | 6 | 19 | 13 | 19 |
| 3 | 14 | 7 | 14 | 15 | 14 |
| 19 | 14 | 7 | 14 | 15 | 14 |
| 3 | 14 | 11 | 14 | 15 | 14 |
| 19 | 14 | 11 | 14 | 15 | 14 |
| 1 | 19 | 6 | 19 | 18 | 19 |
| 4 | 19 | 6 | 19 | 18 | 19 |
| 13 | 5 | 3 | 5 | NULL | NULL |
| 13 | 5 | 9 | 5 | NULL | NULL |
| 5 | 12 | 13 | 12 | NULL | NULL |
| 5 | 12 | 18 | 12 | NULL | NULL |
| 10 | 13 | 19 | 13 | NULL | NULL |
| 2 | 10 | NULL | NULL | NULL | NULL |
| 6 | 4 | NULL | NULL | NULL | NULL |
| 7 | 4 | NULL | NULL | NULL | NULL |
| 12 | 6 | NULL | NULL | NULL | NULL |
| 15 | 7 | NULL | NULL | NULL | NULL |
| 17 | 3 | NULL | NULL | NULL | NULL |
| 21 | 4 | NULL | NULL | NULL | NULL |
+----+------+--------+------+---------+------+
39 rows in set (0.00 sec)
结论:
创建索引
ALTER TABLE book ADD INDEX Y (card);
ALTER TABLE phone ADD INDEX Z (card);
ALTER TABLE book ADD INDEX Y (card);
ALTER TABLE phone ADD INDEX Z (card);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kZnQoEJn-1617521623247)(D:\笔记\MySQL\img\Snipaste_2021-04-01_13-44-17.png)]
JOIN 优化结论
将 left join 看作是两层嵌套 for 循环
创建表
CREATE TABLE staffs(
id INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(24)NOT NULL DEFAULT'' COMMENT'姓名',
`age` INT NOT NULL DEFAULT 0 COMMENT'年龄',
`pos` VARCHAR(20) NOT NULL DEFAULT'' COMMENT'职位',
`add_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT'入职时间'
)CHARSET utf8 COMMENT'员工记录表';
INSERT INTO staffs(`name`,`age`,`pos`,`add_time`) VALUES('z3',22,'manager',NOW());
INSERT INTO staffs(`name`,`age`,`pos`,`add_time`) VALUES('July',23,'dev',NOW());
INSERT INTO staffs(`name`,`age`,`pos`,`add_time`) VALUES('2000',23,'dev',NOW());
ALTER TABLE staffs ADD INDEX index_staffs_nameAgePos(`name`,`age`,`pos`);
mysql> select * from staffs;
+----+------+-----+---------+---------------------+
| id | name | age | pos | add_time |
+----+------+-----+---------+---------------------+
| 1 | z3 | 22 | manager | 2020-08-04 14:42:33 |
| 2 | July | 23 | dev | 2020-08-04 14:42:33 |
| 3 | 2000 | 23 | dev | 2020-08-04 14:42:33 |
+----+------+-----+---------+---------------------+
3 rows in set (0.00 sec)
最佳左匹配法则带头大哥不能死,中间兄弟不能断
而头 name 没挂,第二个 age 没带
key = index_staffs_nameAgePos 说明索引没有失效
ref = const 表明只使用了一个常量,即第二个常量(pos = ‘dev’)没有生效
在索引列上进行计算,会导致索引失效,进而转向全表扫描
范围之后全失效
尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少 select *
SELECT *
的写法,Extra 为nullmysql在使用不等于(!=或者<>)的时候无法使用索引会导致全表扫描
is null,is not null 也无法使用索引
like % 写最右
解决【like ‘%str%’ 】索引失效的问题:覆盖索引
创建表
CREATE TABLE `tbl_user`(
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) DEFAULT NULL,
`age`INT(11) DEFAULT NULL,
`email` VARCHAR(20) DEFAULT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO tbl_user(`name`,`age`,`email`)VALUES('1aa1',21,'[email protected]');
INSERT INTO tbl_user(`name`,`age`,`email`)VALUES('2bb2',23,'[email protected]');
INSERT INTO tbl_user(`name`,`age`,`email`)VALUES('3cc3',24,'[email protected]');
INSERT INTO tbl_user(`name`,`age`,`email`)VALUES('4dd4',26,'[email protected]');
CREATE INDEX idx_user_nameAge ON tbl_user(name, age);
测试覆盖索引
如下 SQL 的索引均不会失效:
只要查询的字段能和覆盖索引扯得上关系,并且没有多余字段,覆盖索引就不会失效
EXPLAIN SELECT name, age FROM tbl_user WHERE NAME LIKE '%aa%';
EXPLAIN SELECT name FROM tbl_user WHERE NAME LIKE '%aa%';
EXPLAIN SELECT age FROM tbl_user WHERE NAME LIKE '%aa%';
EXPLAIN SELECT id FROM tbl_user WHERE NAME LIKE '%aa%';
EXPLAIN SELECT id, name FROM tbl_user WHERE NAME LIKE '%aa%';
EXPLAIN SELECT id, age FROM tbl_user WHERE NAME LIKE '%aa%';
EXPLAIN SELECT id, name, age FROM tbl_user WHERE NAME LIKE '%aa%';
EXPLAIN SELECT * FROM tbl_user WHERE NAME LIKE '%aa%';
EXPLAIN SELECT id, name, age, email FROM tbl_user WHERE NAME LIKE '%aa%';
字符串不加单引号索引失效
少用or,用它连接时会索引失效
创建表
create table test03(
id int primary key not null auto_increment,
c1 char(10),
c2 char(10),
c3 char(10),
c4 char(10),
c5 char(10)
);
insert into test03(c1,c2,c3,c4,c5) values ('a1','a2','a3','a4','a5');
insert into test03(c1,c2,c3,c4,c5) values ('b1','b2','b3','b4','b5');
insert into test03(c1,c2,c3,c4,c5) values ('c1','c2','c3','c4','c5');
insert into test03(c1,c2,c3,c4,c5) values ('d1','d2','d3','d4','d5');
insert into test03(c1,c2,c3,c4,c5) values ('e1','e2','e3','e4','e5');
create index idx_test03_c1234 on test03(c1,c2,c3,c4);
mysql> select * from test03;
+----+------+------+------+------+------+
| id | c1 | c2 | c3 | c4 | c5 |
+----+------+------+------+------+------+
| 1 | a1 | a2 | a3 | a4 | a5 |
| 2 | b1 | b2 | b3 | b4 | b5 |
| 3 | c1 | c2 | c3 | c4 | c5 |
| 4 | d1 | d2 | d3 | d4 | d5 |
| 5 | e1 | e2 | e3 | e4 | e5 |
+----+------+------+------+------+------+
5 rows in set (0.00 sec)
问题:我们创建了复合索引idx_test03_c1234,根据以下SQL分析下索引使用情况?
EXPLAIN SELECT * FROM test03 WHERE c1='a1' AND c2='a2' AND c3='a3' AND c4='a4';
EXPLAIN SELECT * FROM test03 WHERE c4='a4' AND c3='a3' AND c2='a2' AND c1='a1';
EXPLAIN SELECT * FROM test03 WHERE c1='a1' AND c2='a2' AND c4='a4' and c3='a3';
EXPLAIN SELECT * FROM test03 WHERE c1='a1' AND c2='a2' AND c3>'a3' AND c4='a4';
EXPLAIN SELECT * FROM test03 WHERE c1='a1' AND c2='a2' AND c4='a4' ORDER BY c3;
EXPLAIN SELECT * FROM test03 WHERE c1='a1' AND c2='a2' ORDER BY c3;
EXPLAIN SELECT * FROM test03 WHERE c1='a1' AND c2='a2' ORDER BY c4;
EXPLAIN SELECT * FROM test03 WHERE c1='a1' AND c5='a5' ORDER BY c2, c3;
EXPLAIN SELECT * FROM test03 WHERE c1='a1' AND c5='a5' ORDER BY c3, c2;
EXPLAIN SELECT * FROM test03 WHERE c1='a1' AND c2='a2' ORDER BY c2, c3;
EXPLAIN SELECT * FROM test03 WHERE c1='a1' AND c2='a2' AND c5='a5' ORDER BY c2, c3;
EXPLAIN SELECT * FROM test03 WHERE c1='a1' AND c2='a2' AND c5='a5' ORDER BY c3, c2;
EXPLAIN SELECT * FROM test03 WHERE c1='a1' AND c4='a4' GROUP BY c2, c3;
EXPLAIN SELECT * FROM test03 WHERE c1='a1' AND c4='a4' GROUP BY c3, c2;
- group by 基本上都需要进行排序,但凡使用不当,会有临时表产生
- 定值为常量、范围之后失效,最终看排序的顺序
一般性建议
索引优化的总结
全值匹配我最爱, 最左前缀要遵守;
带头大哥不能死, 中间兄弟不能断;
索引列上少计算, 范围之后全失效;
LIKE 百分写最右, 覆盖索引不写 *;
不等空值还有 OR, 索引影响要注意;
VAR 引号不可丢, SQL 优化有诀窍。
永远小表驱动大表,类似嵌套循环 Nested Loop
结论:
in 和 exists 的用法
mysql> select * from tbl_emp;
+----+------+--------+
| id | NAME | deptId |
+----+------+--------+
| 1 | z3 | 1 |
| 2 | z4 | 1 |
| 3 | z5 | 1 |
| 4 | w5 | 2 |
| 5 | w6 | 2 |
| 6 | s7 | 3 |
| 7 | s8 | 4 |
| 8 | s9 | 51 |
+----+------+--------+
8 rows in set (0.00 sec)
mysql> select * from tbl_dept;
+----+----------+--------+
| id | deptName | locAdd |
+----+----------+--------+
| 1 | RD | 11 |
| 2 | HR | 12 |
| 3 | MK | 13 |
| 4 | MIS | 14 |
| 5 | FD | 15 |
+----+----------+--------+
5 rows in set (0.00 sec)
mysql> select * from tbl_emp e where e.deptId in (select id from tbl_dept);
+----+------+--------+
| id | NAME | deptId |
+----+------+--------+
| 1 | z3 | 1 |
| 2 | z4 | 1 |
| 3 | z5 | 1 |
| 4 | w5 | 2 |
| 5 | w6 | 2 |
| 6 | s7 | 3 |
| 7 | s8 | 4 |
+----+------+--------+
7 rows in set (0.00 sec)
mysql> select * from tbl_emp e where exists (select 1 from tbl_dept d where e.deptId = d.id);
+----+------+--------+
| id | NAME | deptId |
+----+------+--------+
| 1 | z3 | 1 |
| 2 | z4 | 1 |
| 3 | z5 | 1 |
| 4 | w5 | 2 |
| 5 | w6 | 2 |
| 6 | s7 | 3 |
| 7 | s8 | 4 |
+----+------+--------+
7 rows in set (0.00 sec)
ORDER BY子句,尽量使用Index方式排序,避免使用FileSort方式排序
创建表
create table tblA(
#id int primary key not null auto_increment,
age int,
birth timestamp not null
);
insert into tblA(age, birth) values(22, now());
insert into tblA(age, birth) values(23, now());
insert into tblA(age, birth) values(24, now());
create index idx_A_ageBirth on tblA(age, birth);
CASE1:能使用索引进行排序的情况
CASE2:不能使用索引进行排序的情况
结论
如果未在索引列上完成排序,mysql 会启动 filesort 的两种算法:双路排序和单路排序
遵循如下规则,可提高Order By的速度
Order By 排序索引优化的总结
慢查询日志是什么?
默认情况下,MySQL 数据库没有开启慢查询日志,需要我们手动来设置这个参数,当然,如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会或多或少带来一定的性能影响。慢查询日志支持将日志记录写入文件
查看是否开启及如何开启
SHOW VARIABLES LIKE '%slow_query_log%';
查看 mysql 的慢查询日志是否开启mysql> SHOW VARIABLES LIKE '%slow_query_log%';
+---------------------+---------------------------------+
| Variable_name | Value |
+---------------------+---------------------------------+
| slow_query_log | OFF |
| slow_query_log_file | /var/lib/mysql/hodoop2-slow.log |
+---------------------+---------------------------------+
2 rows in set (0.12 sec)
如何开启开启慢查询日志:
set global slow_query_log = 1;
开启慢查询日志set global slow_query_log=1
开启了慢查询日志只对当前数据库生效,如果MySQL重启后则会失效。如果要永久生效,就必须修改配置文件my.cnf(其它系统变量也是如此)
[mysqld]
slow_query_log =1
slow_query_log_file=/var/lib/mysql/hodoop2-slow.log
那么开启慢查询日志后,什么样的SQL参会记录到慢查询里面?
SHOW VARIABLES LIKE 'long_query_time%';
查看慢 SQL 的阈值mysql> SHOW VARIABLES LIKE 'long_query_time%';
+-----------------+-----------+
| Variable_name | Value |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set (0.01 sec)
案例
mysql> SHOW VARIABLES LIKE 'long_query_time%';
+-----------------+-----------+
| Variable_name | Value |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set (0.00 sec)
set global long_query_time=3;
show global variables like 'long_query_time';
发现已经生效select sleep(4);#使用sleep函数睡眠4秒,肯定会被记录到日志中
show global status like '%Slow_queries%';
配置版的慢查询日志
在 /etc/my.cnf 文件的 [mysqld] 节点下配置
slow_query_log=1; #开启慢查询日志功能
slow_query_log_file=/var/lib/mysql/Heygo-slow.log #指定日志文件位置
long_query_time=3; #设置阙值
log_output=FILE #输出为文件格式
mysqldumpslow是什么?
在生产环境中,如果要手工分析日志,查找、分析SQL,显然是个体力活,MySQL提供了日志分析工具mysqldumpslow。
查看 mysqldumpslow的帮助信息
[root@Heygo mysql]# mysqldumpslow --help
Usage: mysqldumpslow [ OPTS... ] [ LOGS... ]
Parse and summarize the MySQL slow query log. Options are
--verbose verbose
--debug debug
--help write this text to standard output
-v verbose
-d debug
-s ORDER what to sort by (al, at, ar, c, l, r, t), 'at' is default
al: average lock time
ar: average rows sent
at: average query time
c: count
l: lock time
r: rows sent
t: query time
-r reverse the sort order (largest last instead of first)
-t NUM just show the top n queries
-a don't abstract all numbers to N and strings to 'S'
-n NUM abstract numbers with at least n digits within names
-g PATTERN grep: only consider stmts that include this string
-h HOSTNAME hostname of db server for *-slow.log filename (can be wildcard),
default is '*', i.e. match all
-i NAME name of server instance (if using mysql.server startup script)
-l don't subtract lock time from total time
mysqldumpshow 参数解释
常用参数手册
mysqldumpslow -s r -t 10 /var/lib/mysql/Heygo-slow.log
mysqldumpslow -s c- t 10/var/lib/mysql/Heygo-slow.log
mysqldumpslow -s t -t 10 -g "left join" /var/lib/mysql/Heygo-slow.log
mysqldumpslow -s r -t 10 /var/lib/mysql/Heygo-slow.log | more
创建表
CREATE TABLE dept
(
deptno int unsigned primary key auto_increment,
dname varchar(20) not null default "",
loc varchar(8) not null default ""
)ENGINE=INNODB DEFAULT CHARSET=utf8;
CREATE TABLE emp
(
id int unsigned primary key auto_increment,
empno mediumint unsigned not null default 0,
ename varchar(20) not null default "",
job varchar(9) not null default "",
mgr mediumint unsigned not null default 0,
hiredate date not null,
sal decimal(7,2) not null,
comm decimal(7,2) not null,
deptno mediumint unsigned not null default 0
)ENGINE=INNODB DEFAULT CHARSET=utf8;
设置参数
创建函数,假如报错:This function has none of DETERMINISTIC………
由于开启过慢查询日志,因为我们开启了bin-log,我们就必须为我们的function指定一个参数。
log_bin_trust_function_creators = OFF
,默认必须为 function 传递一个参数
mysql> show variables like 'log_bin_trust_function_creators';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| log_bin_trust_function_creators | OFF |
+---------------------------------+-------+
1 row in set (0.00 sec)
set global log_bin_trust_function_creators=1;
我们可以不用为 function 传参mysql> set global log_bin_trust_function_creators=1;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like 'log_bin_trust_function_creators';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| log_bin_trust_function_creators | ON |
+---------------------------------+-------+
1 row in set (0.00 sec)
创建函数,保证每条数据都不同
delimiter $$ # 自定义两个 $$ 表示结束
create function rand_string(n int) returns varchar(255)
begin
declare chars_str varchar(100) default 'abcdefghijklmnopqrstuvwxyz';
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 $$
create function rand_num() returns int(5)
begin
declare i int default 0;
set i=floor(100+rand()*10);
return i;
end $$
创建存储过程
create procedure insert_emp(in start int(10),in max_num int(10))
begin
declare i int default 0;
set autocommit = 0;
repeat
set i = i+1;
insert into emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) values((start+i),rand_string(6),'salesman',0001,curdate(),2000,400,rand_num());
until i=max_num
end repeat;
commit;
end $$
create procedure insert_dept(in start int(10),in max_num int(10))
begin
declare i int default 0;
set autocommit = 0;
repeat
set i = i+1;
insert into dept(deptno,dname,loc) values((start+i),rand_string(10),rand_string(8));
until i=max_num
end repeat;
commit;
end $$
调用存储过程
DELIMITER ;
CALL insert_dept(100, 10);
DELIMITER ;
CALL insert_emp(100001, 500000);
**原因:**MySQL5.6和MySQL5.7默认的sql_mode模式参数是不一样的,5.6的mode是NO_ENGINE_SUBSTITUTION,其实表示的是一个空值,相当于没有什么模式设置,可以理解为宽松模式,而5.7的mode是STRICT_TRANS_TABLES,也就是严格模式。
select @@sql_mode;
set @@sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
上面是改变了全局sql_mode,对于新建的数据库有效
set sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'
查看是当前的SQL版本是否支持Show Profile
show variables like 'profiling%';
查看 Show Profile 是否开启开启功能 Show Profile ,默认是关闭,使用前需要开启
set profiling=on;
开启 Show Profile,退出客户端就还原了运行 SQL
select * from tbl_emp;
select * from tbl_emp e inner join tbl_dept d on e.deptId = d.id;
select * from tbl_emp e left join tbl_dept d on e.deptId = d.id;
select * from emp group by id%10 limit 150000;
select * from emp group by id%10 limit 150000;
select * from emp group by id%20 order by 5;
查看结果
show profiles;
指令查看结果诊断SQL
show profile [参数1,参数2] for query
查看 SQL 语句执行的具体流程以及每个步骤花费的时间
参数介绍:
日常开发需要注意的结论
永远不要在生产环境开启这个功能
配置启用全局查询日志
# 开启
general_log=1
# 记录日志文件的路径
general_log_file=/path/logfile
# 输出格式
log_output=FILE
编码启用全局查询日志
set global general_log=1;
set global log_output='TABLE';
select * from mysql.general_log;
从数据操作的类型(读、写)分
从对数据操作的颗粒度
**特点:偏向MyISAM存储引擎,开销小,加锁快,无死锁,锁定粒度大,**发生锁冲突的概率最高,并发最低
创建表
create table mylock (
id int not null primary key auto_increment,
name varchar(20) default ''
) engine myisam;
insert into mylock(name) values('a');
insert into mylock(name) values('b');
insert into mylock(name) values('c');
insert into mylock(name) values('d');
insert into mylock(name) values('e');
select * from mylock;
mysql> select * from mylock;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | d |
| 5 | e |
+----+------+
5 rows in set (0.00 sec)
手动加锁和释放锁
查看当前数据库中表的上锁情况:show open tables;
,0 表示未上锁
添加锁
lock table 表名1 [read|write], 表名2 [read|write], ...;
unlock tables;
mysql> lock table mylock read;
Query OK, 0 rows affected (0.00 sec)
--------------------SESSION 1 --------------------
mysql> select * from mylock;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | d |
| 5 | e |
+----+------+
5 rows in set (0.00 sec)
--------------------SESSION 1 --------------------
mysql> select * from book;
ERROR 1100 (HY000): Table 'book' was not locked with LOCK TABLES
--------------------SESSION 2 --------------------
mysql> select * from mylock;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | d |
| 5 | e |
+----+------+
5 rows in set (0.00 sec)
结论
mysql> lock table mylock write;
Query OK, 0 rows affected (0.00 sec)
--------------------SESSION 1 --------------------
mysql> select * from mylock;
+----+------+
| id | name |
+----+------+
| 1 | a2 |
| 2 | b |
| 3 | c |
| 4 | d |
| 5 | e |
+----+------+
5 rows in set (0.00 sec)
--------------------SESSION 1 --------------------
mysql> select * from book;
ERROR 1100 (HY000): Table 'book' was not locked with LOCK TABLES
--------------------SESSION 1 --------------------
mysql> update mylock set name='a2' where id=1;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
mysql> select * from mylock;
#阻塞中
结论
总结
简而言之,读锁会阻塞写,但是不会堵塞读。而写锁则会把读和写都堵塞。
show open tables;
**如何分析表锁定:**可以通过检查table_locks_waited和table_locks_immediate状态变量来分析系统上的表锁定,通过 show status like 'table%';
命令查看
事务(Transation)及其ACID属性
事务是由一组SQL语句组成的逻辑处理单元,事务具有以下4个属性,通常简称为事务的ACID属性
并发事务处理带来的问题
事物的隔离级别
show variables like 'tx_isolation';
mysql 默认是可重复读创建表
CREATE TABLE test_innodb_lock (a INT(11),b VARCHAR(16))ENGINE=INNODB;
INSERT INTO test_innodb_lock VALUES(1,'b2');
INSERT INTO test_innodb_lock VALUES(3,'3');
INSERT INTO test_innodb_lock VALUES(4, '4000');
INSERT INTO test_innodb_lock VALUES(5,'5000');
INSERT INTO test_innodb_lock VALUES(6, '6000');
INSERT INTO test_innodb_lock VALUES(7,'7000');
INSERT INTO test_innodb_lock VALUES(8, '8000');
INSERT INTO test_innodb_lock VALUES(9,'9000');
INSERT INTO test_innodb_lock VALUES(1,'b1');
CREATE INDEX test_innodb_a_ind ON test_innodb_lock(a);
CREATE INDEX test_innodb_lock_b_ind ON test_innodb_lock(b);
操作同一行数据
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> update test_innodb_lock set b='4001' where a=4;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> update test_innodb_lock set b='4002' where a=4;
# 在这儿阻塞着呢~~~
# 时间太长,会报超时错误哦
mysql> update test_innodb_lock set b='4001' where a=4;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
操作不同行数据
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> update test_innodb_lock set b='4001' where a=4;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
session2 开启事务,修改 test_innodb_lock 中不同行的数据
由于采用行锁,session2 和 session1 互不干涉,所以 session2 中的修改操作没有阻塞
索引失效导致行锁升级为表锁
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> update test_innodb_lock set a=44 where b=4000;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> update test_innodb_lock set b='9001' where a=9;
# 在这阻塞了
间隙锁的危害
如何锁定一行
select xxx ... for update
锁定某一行后,其它的操作会被阻塞,直到锁定行的会话提交mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from test_innodb_lock where a=8 for update;
+------+------+
| a | b |
+------+------+
| 8 | 8000 |
+------+------+
1 row in set (0.00 sec)
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> update test_innodb_lock set b='XXX' where a=8;
# 在这儿阻塞着呢~~~
案例结论
Innodb存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面所带来的性能损耗可能比表级锁定会要更高一些,但是在整体并发处理能力方面要远远优于MyISAM的表级锁定的
当系统并发量较高的时候,Innodb的整体性能和MyISAM相比就会有比较明显的优势了。
但是,Innodb的行级锁定同样也有其脆弱的一面,当我们使用不当的时候(索引失效,导致行锁变表锁),可能会让Innodb的整体性能表现不仅不能比MyISAM高,甚至可能会更差
行锁分析
show status like 'innodb_row_lock%';
mysql> show status like 'innodb_row_lock%';
+-------------------------------+--------+
| Variable_name | Value |
+-------------------------------+--------+
| Innodb_row_lock_current_waits | 0 |
| Innodb_row_lock_time | 212969 |
| Innodb_row_lock_time_avg | 42593 |
| Innodb_row_lock_time_max | 51034 |
| Innodb_row_lock_waits | 5 |
+-------------------------------+--------+
5 rows in set (0.00 sec)
对各个状态量的说明如下:
主要
尤其是当等待次数很高,而且每次等待时长也不小的时候,我们就需要分析系统中为什么会有如此多的等待,然后根据分析结果着手指定优化计划
slva会从master读取binlog来进行数据同步,主从复制的三步骤
前提:mysql 版本一致,且能够相互通信
必须配置
server-id=1
log-bin=C:/Program Files (x86)/MySQL/MySQL Server 5.5/log-bin/mysqlbin
可选配置
log-err=C:/Program Files (x86)/MySQL/MySQL Server 5.5/log-bin/mysqlerr
basedir="C:/Program Files (x86)/MySQL/MySQL Server 5.5/"
tmpdir="C:/Program Files (x86)/MySQL/MySQL Server 5.5/"
datadir="C:/Program Files (x86)/MySQL/MySQL Server 5.5/Data/"
read-only=0
binlog-ignore-db=mysql
binlog-do-db=需要复制的主数据库名字
从机修改 my.cnf 配置文件(Linux)
server-id=2
修改配置文件后的准备工作
#windows
net stop mysql
net start mysql
service mysqld restart #centos6
systemctl restart mysqld #centos7
注意主机和从机的防火墙设置,要么都关闭要么设置开放端口号
在 Windows 主机上简历账户并授权 slave
REPLICATION
权限(从主机的数据库表中复制表)GRANT REPLICATION SLAVE ON *.* TO '备份账号'@'从机器数据库 IP' IDENTIFIED BY '账号密码';
flush privileges;
select * from mysql.user where user='Heygo'\G;
命令可查看:从机只有 Repl_slave_priv
权限为 Y
,其余权限均为 N
在 Linux 从上验证是否能登陆主机的 MySQL
mysql -h <指定IP地址> -<用户名> -p
命令,发现无法连接主机的 MySQL 数据库在 Linux 从机上配置需要复制的主机
CHANGE MASTER TO
MASTER_HOST='主机 IP',
MASTER_USER='创建用户名',
MASTER_PASSWORD='创建的密码',
MASTER_LOG_FILE='File 名字',
MASTER_LOG_POS=Position数字;
start slave;
show slave status\G;
命令查看 Slave_SQL_Running:Yes
和 Slave_IO_Running:Yes
说明从机连接主机成功(第一次测试没有成功,这是隔了半年之后的测试,因此某些数据会有出入)stop slave;
本内容参考视频
全文参考内容