Mysql 开启远程访问 给指定数据库创建用户并授权

Mysql 8.0

#创建用户 db_user 换成root表示root用户
MySQL [(none)]> create user db_user@'%' identified by 'db_pass';

#授权  db_name 用*替代表示访问所有数据库
MySQL [(none)]> grant all privileges on db_name.* to db_user@'%' with grant option; 

#退出数据库控制台,特别注意有分号
MySQL [(none)]> exit;

Mysql 8.0以下

MySQL [(none)]> grant all privileges on db_name.* to db_user@'%' identified by 'db_pass';
 
#授权语句,特别注意有分号
MySQL [(none)]> flush privileges;

#退出数据库控制台,特别注意有分号
MySQL [(none)]> exit;

创建用户

create user 'username'@'%' identified by 'password';
username 用户名 %所有ip password 密码

授权所有数据库

grant all privileges on *.* to 'username'@'%';

flush privileges;

Mysql 锁的介绍和使用

参考

基本概念

并发

网络编程中,多个请求/查询(进程/线程) 修改同一数据时,就会产并发控制问题,即谁先修改谁后修改.锁机制就是用来解决和控制并发问题的.

Mysql根据加锁的范围(粒度)分为三种锁

全局锁

给整个数据库加锁

FLUSH TABLES WITH READ LOCK
//全局读锁,会使其它线程中的写操作 数据更新语句(删除更新) 数据定义语句(创建修改表) 和更新事物提交类语句被阻塞
//使用场景全库逻辑备份,存在无事物的存储引擎的数据库
mysqldump –single-transaction 适合全库innodb引擎(所有表都支持事物)备份

表级锁

一种是表锁,一种是元数据锁(meta data lock,MDL)

表锁 lock tables tablename… read/write 释放所unlock tables

表锁不仅仅会锁定其它线程对锁定表的操作,也会锁定当前执行lock 语句的线程接下里的操作对象.只能执行当前表的操作

当前线程锁定users表,无法操作其它表
其它线程可以正常读取users表

上图示例当前线程执行了所锁定users表,则无法查询或操作其它表,

此时其它线程中可以正常读取users表的数据,因为读锁不互斥.

锁定执行写操作
释放表锁
另一线程内的查询操作

上三图表示线程A锁定users表示,其它线程对users表的操作,在未释放表锁前,另一线程一直处于阻塞状态,直到释放表锁

另一类表级的锁是MDL(meta data lock)

不需要显示调用,数据库自动操作 Mysql5.5版本中开始引入.作用是保证读写的正确性.例如,一个线程进行遍历查询,另一个线程进行表结构变更.

对一个表进行增删改查操作时,加MDL读锁,对表执行结构变更时,加MDL写锁.

读锁之间不互斥,因此多个线程可以对同一张表做增删改查,

读写锁之间,读锁之间互斥,用户保证表结构变更操作的安全性.例如线程A进行表遍历查询,线程B进行表结构变更操作,线程B需要等线程A的读锁释放之后才能执行

MDL测试案例

测试数据20万
测试代码,事务中遍历数据表
sessionA执行代码中的数据表遍历
sessionB执行Alter语句修改users表结构

此时,sessionB会阻塞,因为sessionA中的MDL读锁还没有被释放

sessoinC中的所有查询都处于等待状态

sessionC所有查询被被阻塞,此时整个数据库不能正常查询,这就是生产环境数据库结构变更可能会踩的坑.

解决方案

1.解除长事务,变更前查询一下存在事物正在运行的事物(information_schema 库的 innodb_trx表),手动kill调.

2.alter table语句设定等待时间. MariaDB和AliSQL支持 DDL NOWWAIT?WAIT n 语法

ALTER TABLE tbl_name NOWAIT add column...

ALTER TABLE tbl_name WAIT n add column...

MDL总结

mysql 5.6之前的版本,执行alter语句时间会很长,通过建立新的临时表方案解决,导入数据,最后重命名.

mysql5.6引入online ddl,通常情况下不会锁库,但是存在长事务和慢查询时,也会出现

行锁

行锁是由存储引擎层实现的,是mysql最小锁定粒度,可以锁定一行数据.常用引擎Innodb支持行锁MyISAM不支持行锁

Innodb行锁介绍

两阶段加锁,,

Mysql 复制 Replication

参考

简介

复制是mysql自带数据同步功能,可用于构建大规模高可用Mysql集群.复制解决的基本问题就是将一台数据库上的数据同步到另一台数据库上.

解决的问题(应用场景)

1.数据分布,备份

在不同的数据中心存储备份数据,即使在不稳定的网络环境中,复制可以正常工作

作为数据备份的补充技术手段

2.负载均衡

解决读密集型业务,将读取请求分发到多台数据库服务器上

3.高可用和故障切换

避免单点问题一台数据库服务器宕机还有其它从库可用

4.mysql升级测试

升级更高版本的mysql时,使用一台备库升级测试,不影响正常业务使用.

工作原理和复制的方式

1. master(主实例)将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events)

2. slave(从实例)将master的binary log events拷贝到它的中继日志(relay log);

3.slave重做中继日志中的事件,更新数据,完成数据同步

复制方式

https://dev.mysql.com/doc/refman/5.7/en/replication-sbr-rbr.html#replication-sbr-rbr-sbr-disadvantages


复制的方式
基于语句的复制(SBR)基于行的复制(RBR)
简介复制的执行Sql语句(逻辑复制)复制数据
优点1.成熟的技术
2.写入日志文件的数据较少(快地完成从备份中获取和恢复) 传输效率更高
3.日志文件包含进行任何更改的所有语句,因此可用于审计数据库(云数据库的sql审计应该是这样实现的?)
1.可以复制所有更改,安全考高
2.执行效率高,因为复制的是数据,没有消耗系统资源的Sql操作

缺点 安全性差一点,有些特殊语句可能会报错
消耗系统资源,主库的操作需要从库要做一遍,
日志文件大传输效率低,I/O操作耗时高

Mysql支持混合复制模式,动态切换语句复制和行复制

复制拓扑及配置

基本原则

  • Mysql一个备库实例只能有一个主库(只能从一个主库读取binlog)(5.7以后支持多源复制)
  • 每一个备库必须有一个唯一服务器ID(同一网络内)
  • 一个主库实例可以有多个备库(一个备库可以有多个兄弟备库)
  • 开启log_slave_updates 选项 备库可以把它从主库获取的数据变化传递给其它备库(slave 此备库的其它备库)

学习拓扑图是,可以把复制的slave关系理解为面向对象中继承关系

一主多从

常用读写分离,适用于多读少写

双主复制

用于多写场景时,需要更改主键自增策略

其它形式的复制,请参考高性能<<Mysql>>

配置(主从实例)

1.创建复制账号

#创建用户
CREATE USER 'tongbu'@'192.168.%.%' IDENTIFIED BY '123456';
#配置账号同步权限
GRANT REPLICATION SLAVE ON *.* TO 'tongbu'@'192.168.%.%';
#刷新权限
flush privileges

需要在主库和从库 执行上述操作

2更改配置文件

配置

#服务器id(保证主从的id都是唯一的)
server-id = 1
#开启binlog日志
log_bin = mysql-bin
#混合复制模式,支持语句复制和行复制
binlog_format = mixed
#备库记录更新
log-slave-updates = 1

查看主库日志和位置 show master status\G

MySQL [(none)]> show master status\G;
*************************** 1. row ***************************
File: mysql-bin.000320
Position: 154
Binlog_Do_DB: 
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 2d8be082-e379-11e6-9e2c-d89d672bc9d4:1-759145,
48496646-e379-11e6-9e2d-008cfaf6f158:1-4,
7c64616c-23a4-11e7-809c-7cd30abda0c4:1-9629173,
98d692c9-07a7-11e7-8a1b-7cd30abd9f90:1-6919876
1 row in set (0.00 sec)

配置从库监听主库

change master to master_host='192.168.31.106',master_port=3306,master_user='tongbu',master_password='123456',master_log_file='mysql-bin.000320',master_log_pos=154;

master_log_file 和 master_log_pos 要根据主库的信息来设置

 #开启从库
 start slave;
 #查看从库状态
 show slave status\G; 
 #状态为yes表示成功 
 Slave_IO_Running: Yes
 Slave_SQL_Running: Yes

开启从库root用户远程访问(方便测试时用户端查看数据)

use mysql;
GRANT ALL ON *.* TO root@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
flush privileges;

测试

创建测试数据库 sync_test 刷新从库, 同步成功

注意

开启start slave 之前的数据不会同步,需要手动在从库创建并导入

MySql索引的使用总结

所有存储引擎都支持每个表至少 16 个索引,总索引长度至少为 256 字节。

组合索引KEY(col1,col2) 联合主键索引 PARIMARY KEY( col1,col2) 

最左匹配原则

创建了key(k1,k2,k3),相当于创建了(k1)、(k1,k2) 和 (k1,k2,k3) 三个索引

索引全部命中的情况where条件不区分顺序 where k1 = xxx and k2 = xxx and k3 = xxx 等同于 where k3 = xxx and k2 = xxx  and k1 = xxx 查询优化器会处理并使用索引

where k1 = xxx 或 where k1 = xxx and k2 = xxx 使用索引 where k2 = xxx 或 where k3 = xxx 无法使用索引

当查询优化器发现最优索引时,并不会遵循最左匹配原则,而是使用最优查询,如下图k1,k2,k3为连续字段时,不按最左匹配查询还是会命中索引,此时k1,k2,k3被查询优化器当成了一个字段,单次查询k1,k2,k3都会命中

EXPLAIN select * from 3k where k2 = 'sdfdsa'

当k1,k2,k3不在连续中间被其它字段隔开时

相同的查询语句将不会命中索引

联合索引,那么 key 也由多个列组成,同时,索引只能用于查找 key 是否存在(相等),遇到 范围查询(>、<、between、like 左匹配)等就不能进一步匹配了,后续退化为线性查找。因此,列的排列顺序决定了可命中索引的列数。

如有索引 (a, b, c, d),查询条件 a = 1 and b = 2 and c = 3 and d > 4,则会在每个节点依次命中 a、b、c,无法命中 d。也就是最左前缀匹配原则。

不需要考虑 =、in 等的顺序,MySQL 会自动优化这些条件的顺序,以匹配尽可能多的索引列。

如有索引 (a, b, c, d),查询条件 c > 3 and b = 2 and a = 1 and d < 4 与 a = 1 and c > 3 and b = 2 and d < 4 等顺序都是可以的,MySQL 会自动优化为 a = 1 and b = 2 and c > 3 and d < 4,依次命中 a、b。

离散度高原则,选择性(离散性)高的优先,即数据重复率低的列,像性别字段只有男/女两个值,因此选择性很差

离散度的公式是 count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是 1,而一些状态、性别字段可能在大数据面前区分度就是 0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要 join 的字段我们都要求是 0.1 以上,即平均 1 条扫描 10 条记录。

索引前缀

字符串字段过长时可以使用,索引前缀,截取字段前一部分的值作为索引

CREATE TABLE test (blob_col BLOB, INDEX(blob_col(10)));

Range类型 要使用单字段索引

当使用 =、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN、LIKE 或 IN() 运算符中的任何一个将键列与常量进行比较时,可以使用范围

where min <= 1 and max >= 1 语句使用min和max联合索引并不会生效,应该使用min和max的两个单字段索引

索引失效情况总结

查询条件包含 or,会导致索引失效

隐式类型转换,会导致索引失效,where条件左边字段类型为字符串类型时,传入其他类型会触发

like 通配符会导致索引失效,注意:”ABC%” 不会失效,会走 range 索引,”% ABC” 或 “%ABC%” 索引会失效

联合索引,最左匹配原则被中断时

对索引字段进行函数运算,列运算(算术,逻辑,移位等) 注意是对字段做运算,对字段的值做运算时并不影响,如下图

索引字段上使用(!= 或者 < >,not in)时,会导致索引失效

索引字段上使用 is null, is not null,可能导致索引失效

相 join 的两个表的字符编码不同,不能命中索引,会导致笛卡尔积的循环计算

mysql 优化器判断使用全表扫描要比使用索引快,则不使用索引

简单索引和联合索引如何抉择?

能扩展就不要新建索引。如果已有索引 (a),想建立索引 (a, b),尽量选择修改索引 (a) 为索引 (a, b),这样占用空间最小效果一致。

如果已有索引 (a, b),则不需要再建立索引 (a),但是如果有必要,则仍然需考虑建立索引 (b)。

索引尽量少原则

虽说索引可以加速查询,但索引未必是越多越好,因为:

  • 第一点、数据的增删都会涉及到随索引的修改,索引越多维护成本越高,所以频繁进行数据操作的表,不要建立太多的索引;
  • 第二点、索引越多也意味着存储空间需要越大;

因为索引是有代价的,所以用不到的索引,也需要清理掉。

如何定位哪些页面和接口需要加索引?

最简单直接方法是:往数据库里生成 100 万条数据,然后做黑盒测试。

数据有了以后,假装你是一个正常的用户,然后不断地点来点去,做各种操作,点赞、收藏、发文章、评论等,看看哪个动作或者页面加载很慢,就记录下来

如果使用laravel框架可以用telescope或者debug工具查看执行的sql语句,对访问频率高的接口和页面,增加索引,优化查询

参考

盘点那些被问烂了的 Mysql 面试题

MySQL 规约(转自阿里巴巴 Java 开发手册)

官方手册优化与索引

laravel优化教程

Mysql Explain命令

官方手册 :https://dev.mysql.com/doc/refman/8.0/en/using-explain.html

Explain命令 查看语句的执行计划,用于sql语句优化

属性说明:

select_type:select 的语句的查询类型

类型值类型值说明

SIMPLE

简单SELECT(不使用UNION或子查询等)

PRIMARY

最外面的SELECT

UNION

UNION中的第二个或后面的SELECT语句

DEPENDENT UNION

UNION中的第二个或后面的SELECT语句,取决于外面的查询

UNION RESULT

UNION的结果

SUBQUERY

子查询中的第一个SELECT

DEPENDENT SUBQUERY

子查询中的第一个SELECT,取决于外面的查询

DERIVED派生表
DEPENDENT DERIVED派生表依赖于另一个表
MATERIALIZED物化子查询,子查询来自视图
UNCACHEABLE SUBQUERY一个子查询,其结果不能被缓存,必须对外层查询的每一行进行重新评估
UNCACHEABLE UNIONUNION中的第二个或以后的选择,属于不可缓存的子查询(参见不可缓存的子查询)

table:显示这一行的数据是关于哪张表的

partitions: 被查询记录所在的分区,没有返回null,分区功能参考mysql分区功能

type:这列最重要,显示了连接使用了哪种类别,有无使用索引,是使用Explain命令分析性能瓶颈的关键项之一

类型值类型值说明
system该表只有一行(= 系统表)。这是 const 连接类型的特例
const该表最多有一个匹配行,在查询开始时读取。因为只有一行,该行中该列的值可以被优化器的其余部分视为常量。 const 表非常快,因为它们只被读取一次。主键或唯一索引时类型为常量
eq_ref对于前面表中的每个行组合,从该表中读取一行。除了 system 和 const 类型之外,这是最好的连接类型。当连接使用索引的所有部分并且索引是 PRIMARY KEY 或 UNIQUE NOT NULL 索引时使用它
ref所有具有匹配索引值的记录都从这个表中读出,用于前面表中的每一个记录组合。如果连接只使用键的最左边的前缀,或者键不是PRIMARY KEY或UNIQUE索引(换句话说,如果连接不能根据键值选择一条记录),就使用ref。如果使用的键只与几条记录相匹配,这就是一个好的连接类型
fulltext全文索引,类搜索引擎功能
ref_or_null这种连接类型就像ref,但增加了MySQL对包含NULL值的行进行额外的搜索。这种连接类型的优化在解决子查询时最常使用。在下面的例子中,MySQL可以使用一个ref_or_null连接来处理ref_table
index_merge这种连接类型表明使用了索引合并优化。在这种情况下,输出行中的key列包含了所使用的索引的列表,key_len包含了所使用的索引的最长的key部分的列表。更多信息,请参见章节8.2.1.3,”索引合并优化
unique_subquery对于以下形式的某些 IN 子查询,此类型替换 eq_ref:value IN (SELECT primary_key FROM single_table WHERE some_expr)
index_subquery这种连接类型类似于 unique_subquery。它取代了 IN 子查询,但它适用于以下形式的子查询中的非唯一索引:value IN (SELECT key_column FROM single_table WHERE some_expr)
range只检索给定范围内的行,使用索引来选择行。输出行中的key列表明使用的是哪个索引。key_len包含了所使用的最长的关键部分。对于这种类型,ref列是NULL
index索引连接类型与ALL相同,只是对索引树进行扫描。这有两种情况。
如果索引是查询的覆盖索引,并且可以用来满足表的所有数据要求,那么只有索引树被扫描。在这种情况下,Extra列显示使用索引。只扫描索引的速度通常比ALL快,因为索引的大小通常比表的数据小。
全表扫描是使用从索引中读出的数据来按索引顺序查找数据行。使用索引不会出现在Extra列中。
当查询只使用属于一个索引的列时,MySQL可以使用这种连接类型。
ALL没有使用任何索引,使用了全表扫描,性能非常差

range示例说明

当使用 =、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN、LIKE 或 IN() 运算符中的任何一个将键列与常量进行比较时,可以使用范围:
SELECT * FROM tbl_name
  WHERE key_column = 10;

SELECT * FROM tbl_name
  WHERE key_column BETWEEN 10 and 20;

SELECT * FROM tbl_name
  WHERE key_column IN (10,20,30);

SELECT * FROM tbl_name
  WHERE key_part1 = 10 AND key_part2 IN (10,20,30);

结果值从好到坏依次是:一般来说,得保证查询至少达到range级别,最好能达到ref,否则就可能会出现性能问题。

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

possible_keys:列指出MySQL能使用哪个索引在该表中找到行

当前查询可用的索引 多个逗号分隔

key:显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL

查询优化器实际选择的索引

key_len:显示MySQL决定使用的键长度。如果键是NULL,则长度为NULL。使用的索引的长度。在不损失精确性的情况下,长度越短越好

ref:显示使用哪个列或常数与key一起从表中选择

ref列显示哪些列或常量与列中指定的索引进行比较以 key从表中选择行。

如果值为func,则使用的值是某个函数的结果。要查看哪个功能,请使用 SHOW WARNINGS以下内容 EXPLAIN查看扩展 EXPLAIN输出。该函数实际上可能是一个运算符,例如算术运算符。

rows: rows列表示MySQL认为它必须检查以执行查询的行数,对于InnoDB表,这个数字是一个估计值,不一定准确

filtered: 表按照条件过滤行数的百分比

过滤列表示被表条件过滤的表行的估计百分比。最大值是100,这意味着没有发生过滤的行。从100开始递减的值表示过滤量的增加。rows显示了被检查的行的估计数量,rows × filtered显示了与下面表格连接的行的数量。例如,如果rows是1000,而filtered是50.00(50%),那么与下表中连接的行数是1000×50%=500

Extra:附加信息 包含MySQL解决查询的详细信息,也是关键参考项之一。

这一列包含关于MySQL如何解决查询的额外信息。关于不同值的描述,见EXPLAIN额外信息。

没有与Extra列相对应的单一JSON属性;然而,可能出现在这一列中的值被暴露为JSON属性,或作为消息属性的文本

具体信息看官方文档查询

https://dev.mysql.com/doc/refman/8.0/en/explain-output.html#explain-extra-information

其他一些Tip:

  1. 当type 显示为 “index” 时,并且Extra显示为“Using Index”, 表明使用了覆盖索引。

EXPLAIN ANALYZE

select * 和 select 具体字段差别