如果查询缓存有命中的查询结果,查询语句就可以直接去查询缓存中取数据。这个缓存机制是由一系列小缓存组成的。比如表缓存,记录缓存,key缓存,权限缓存等
存储引擎接口
存储引擎接口模块可以说是 MySQL 数据库中最有特色的一点了。目前各种数据库产品中,基本上只有 MySQL 可以实现其底层数据存储引擎的插件式管理。这个模块实际上只是 一个抽象类,但正是因为它成功地将各种数据处理高度抽象化,才成就了今天 MySQL 可插拔存储引擎的特色。
从图还可以看出,MySQL区别于其他数据库的最重要的特点就是其插件式的表存储引擎。MySQL插件式的存储引擎架构提供了一系列标准的管理和服务支持,这些标准与存储引擎本身无关,可能是每个数据库系统本身都必需的,如SQL分析器和优化器等,而存储引擎是底层物理结构的实现,每个存储引擎开发者都可以按照自己的意愿来进行开发。
注意:存储引擎是基于表的,而不是数据库。
1.2 逻辑架构图2
1.3 执行流程图
1.4 存储引擎介绍
锁 表锁、行锁 表锁
事务 ACID 不支持
CRDU 读、写 读多
count 扫表 专门存储的地方
索引结构 B+ Tree B+ Tree
Innodb | Myisam | |
---|---|---|
存储文件 | .frm 表定义文件 .ibd 数据文件 | .frm 表定义文件 .myd 数据文件 .myi 索引文件 |
锁 | 表锁、行锁 | 表锁 |
事务 | ACID | 不支持 |
CRDU | 读、写 | 读多 |
count | 扫表 | 专门存储的地方 |
索引结构 | B+ Tree | B+ Tree |
1.5 mysql物理结构
1.6 数据文件
查看MySQL数据文件:SHOW VARIABLES LIKE ‘%datadir%’;
2.1 介绍
2.2 索引的分类
单列索引:
* 普通索引:MySQL中基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值,纯粹为了查询数据更快一点。
* 唯一索引:索引列中的值必须是唯一的,但是允许为空值,
* 主键索引:是一种特殊的唯一索引,不允许有空值。
组合索引
*在表中的多个字段组合上创建的索引,只有在查询条件中使用了这些 字段的左边字段时,索引才会被使用,使用组合索引时遵循最左前缀集合。
*全文索引 全文索引,只有在MyISAM引擎上才能使用,只能在CHAR,VARCHAR,TEXT类型字段上使用全文索引。
*空间索引:不做介绍,一般使用不到。
2.3 索引的使用
2.4索引的存储结构
参考链接
2.5使用索引的注意事项
2.6 MySQL性能优化之查看执行计划explain
2.6.1 介绍
2.6.3 select_type列说明
2.6.4 type列说明
通常来说, 不同的 type 类型的性能关系如下:
ALL < index < range ~ index_merge < ref < eq_ref < const < system
类型 | 含义 |
---|---|
system | 表只有一行 |
const | 表最多只有一行匹配,通用用于主键或者唯一索引比较时 |
eq_ref | 每次与之前的表合并行都只在该表读取一行,这是除了system const之外最好的一种,特点是使用=,而且索引的所有部分都参与join且索引是主键或非空唯一键的索引 |
ref | 如果每次只匹配少数行,那就是比较好的一种,使用=或<=>,可以是左覆盖索引或非主键或非唯一键 |
fulltext | 全文搜索 |
ref_or_null | 与ref类似,但包括NULL |
index_merge | 表示出现了索引合并优化(包括交集,并集以及交集之间的并集),但不包括跨表和全文索引。这个比较复杂,目前的理解是合并单表的范围索引扫描(如果成本估算比普通的range要更优的话 |
unique_subquery | 在in子查询中,就是value in (select…)把形如“select unique_key_column”的子查询替换。PS:所以不一定in子句中使用子查询就是低效的! |
index_subquery | 同上,但把形如”select non_unique_key_column“的子查询替换 |
range | 常数值的范围 |
index | a.当查询是索引覆盖的,即所有数据均可从索引树获取的时候(Extra中有Using Index)b.以索引顺序从索引中查找数据行的全表扫描(无 Using Index)c.如果Extra中Using Index与Using Where同时出现的话,则是利用索引查找键值的意思;d.如单独出现,则是用读索引来代替读行,但不用于查找 |
all | 全表扫描 |
3.1 性能优化思路
首先需要使用慢查询功能,去获取所有查询时间比较长的SQL语句
3.2介绍
3.3开启慢查询功能
查看是否开启慢查询功能
参数说明
*slow_query_log :是否开启慢查询日志,ON 为开启,OFF 为关闭,如果为关闭可以开启。
*log-slow-queries :旧版(5.6以下版本)MySQL数据库慢查询日志存储路径。可以不设置该参数,系统则会默认给一个缺省的文件host_name-slow.log
*slow-query-log-file:新版(5.6及以上版本)MySQL数据库慢查询日志存储路径。可以不设置该参数,系统则会默认给一个缺省的文件host_name-slow.log
*long_query_time :慢查询阈值,当查询时间多于设定的阈值时,记录日志,单位为秒。
永久开启慢查询功能
修改/etc/my.cnf配置文件,重启 MySQL, 这种永久生效.
[mysqld]
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
慢查询日志格式
格式说明:
*第一行,SQL查询执行的时间
*第二行,执行SQL查询的连接信息,用户和连接IP
*第三行,记录了一些我们比较有用的信息,如下解析
Query_time,这条SQL执行的时间,越长则越慢
Lock_time,在MySQL服务器阶段(不是在存储引擎阶段)等待表锁时间
Rows_sent,查询返回的行数
Rows_examined,查询检查的行数,越长就当然越费时间
*第四行,设置时间戳,没有实际意义,只是和第一行对应执行时间。
*第五行及后面所有行(第二个# Time:之前),执行的sql语句记录信息,因为sql可能会很长。
分析慢查询日志
1.MySQL自带的mysqldumpslow
[root@localhost mysql]# mysqldumpslow /var/lib/mysql/localhost-slow.log
2.常用参数说明
实例:
得到按照时间排序的前10条里面含有左连接的查询语句。
mysqldumpslow -s t -t 10 -g “left join” /var/lib/mysql/localhost_slow.log
通常我们是使用的explain,以及slow query log都无法做到精确分析,但是Query Profiler却可以定位出一条SQL语句执行的各种资源消耗情况,比如CPU,IO等,以及该SQL执行所耗费的时间等
4.1语句使用
show profile 和 show profiles 语句可以展示当前会话(退出session后,profiling重置为0) 中执行语句的资源使用情况.
show profiles :以列表形式显示最近发送到服务器上执行的语句的资源使用情况.显示的记录数由变量:profiling_history_size 控制,默认15条
show profile: 展示最近一条语句执行的详细资源占用信息,默认显示 Status和Duration两列
4.2 开启Profile功能
Profile 功能由MySQL会话变量 : profiling控制,默认是OFF关闭状态。
5.1 事务概叙
5.2一般来说,事务是必须满足4个条件(ACID):
5.3 mysql事务支持
在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作。因此要显式地开启一个事务务须使用命令 BEGIN 或 START TRANSACTION,或者执行命令 SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交。
5.4 事务并发出现的常见问题
5.5 事务并发出现的问题处理(事务隔离级别)
现在来看看MySQL数据库为我们提供的四种隔离级别(由低到高):
① Read uncommitted (读未提交):最低级别,任何情况都无法保证。
② Read committed (读已提交):可避免脏读的发生。
③ Repeatable read (可重复读):可避免脏读、不可重复读的发生。
④ Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
5.6 默认隔离级别
大多数数据库的默认隔离级别是Read committed,比如Oracle、DB2等。
MySQL数据库的默认隔离级别是Repeatable read。
5.7 查看设置隔离级别
5.8 注意事项
6.1锁介绍
数据库锁定机制简单来说就是数据库为了保证数据的一致性而使各种共享资源在被并发访问访问变得有序所设计的一种规则。
对于任何一种数据库来说都需要有相应的锁定机制,所以MySQL自然也不能例外。
MySQL数据库由于其自身架构的特点,存在多种数据存储引擎,每种存储引擎所针对的应用场景特点都不太一样,为了满足各自特定应用场景的需求,每种存储引擎的锁定机制都是为各自所面对的特定场景而优化设计,所以各存储引擎的锁定机制也有较大区别。
总的来说,MySQL各存储引擎使用了三种类型(级别)的锁定机制:行级锁定,页级锁定和表级锁定。下面我们先分析一下MySQL这三种锁定的特点和各自的优劣所在。
6.2 行级锁定
行级锁定最大的特点就是锁定对象的颗粒度很小,也是目前各大数据库管理软件所实现的锁定颗粒度最小的。由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。
虽然能够在并发处理能力上面有较大的优势,但是行级锁定也因此带来了不少弊端。由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。
6.3 表级锁定
和行级锁定相反,表级别的锁定是MySQL各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。由于表级锁一次会将整个表锁定,所以可以很好的避免困扰我们的死锁问题。
当然,锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也会最高,致使并大度大打折扣。
6.4 页级锁定
页级锁定是MySQL中比较独特的一种锁定级别,在其他数据库管理软件中也并不是太常见。页级锁定的特点是锁定颗粒度介于行级锁定与表级锁之间,所以获取锁定所需要的资源开销,以及所能提供的并发处理能力也同样是介于上面二者之间。另外,页级锁定和行级锁定一样,会发生死锁。
6.5 表级锁
6.5.1 手动增加表锁
lock table 表名称 read(write),表名称2 read(write),其他;
6.5.2 查看表锁状况
show open tables;
6.5.3 删除表锁
unlock tables;
6.8 InnoDB引擎的锁机制
共享锁(S读锁):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
排他锁(X写锁):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。
意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。
说明:
1)共享锁和排他锁都是行锁,意向锁都是表锁,应用中我们只会使用到共享锁和排他锁,意向锁是mysql内部使用的,不需要用户干预。
2)对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);对于普通SELECT语句,InnoDB不会加任何锁,事务可以通过以下语句显示给记录集加共享锁或排他锁。
共享锁(S):SELECT * FROM table_name WHERE … LOCK IN SHARE MODE。
排他锁(X):SELECT * FROM table_name WHERE … FOR UPDATE。
3)InnoDB行锁是通过给索引上的索引项加锁来实现的,因此InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!。
6.9 InnoDB行锁演示
mysql> create table test_innodb_lock (a int(11),b varchar(16)) engine=innodb;
Query OK, 0 rows affected (0.02 sec)
mysql> create index test_innodb_a_idx on test_innodb_lock(a);
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> create index test_innodb_lock_b_idx on test_innodb_lock(b);
Query OK, 11 rows affected (0.01 sec)
Records: 11 Duplicates: 0 Warnings: 0
行锁基本演示 | Session a | Session b |
---|---|---|
1 | mysql> set autocommit=0;Query OK, 0 rows affected (0.00 sec) | mysql> set autocommit=0;Query OK, 0 rows affected (0.00 sec) |
mysql> update test_innodb_lock set b = ‘b1’ where a = 1;Query OK, 1 row affected (0.00 sec)Rows matched: 1 Changed: 1 Warnings: 0 更新,但是不提交 | ||
2 | mysql> update test_innodb_lock set b = ‘b1’ where a = 1;被阻塞,等待 | |
3 | mysql> commit; Query OK, 0 rows affected (0.05 sec) 提交 | |
4 | mysql> update test_innodb_lock set b = ‘b1’ where a = 1;Query OK, 0 rows affected (36.14 sec)Rows matched: 1 Changed: 0 Warnings: 0 解除阻塞,更新正常进行 | |
无索引升级为表锁演示 | ||
5 | mysql> update test_innodb_lock set b = ‘2’ where b = 2000;Query OK, 1 row affected (0.02 sec) Rows matched: 1 Changed: 1 Warnings: 0 | mysql> update test_innodb_lock set b = ‘3’ where b = 3000;被阻塞,等待 |
6 | ||
7 | mysql> commit; Query OK, 0 rows affected (0.10 sec) | |
8 | mysql> update test_innodb_lock set b = ‘3’ where b = 3000;Query OK, 1 row affected (1 min 3.41 sec) Rows matched: 1 Changed: 1Warnings: 0阻塞解除,完成更新 | |
间隙锁带来的插入问题演示 | ||
9 | mysql> update test_innodb_lock set b = a * 100 where a < 4 and a > 1;Query OK, 1 row affected (0.02 sec) Rows matched: 1 Changed: 1 Warnings: 0 | |
10 | mysql> insert into test_innodb_lock values(2,‘200’);被阻塞,等待 | |
11 | mysql> commit;Query OK, 0 rows affected (0.02 sec) | |
12 | mysql> insert into test_innodb_lock values(2,‘200’);Query OK, 1 row affected(38.68 sec)阻塞解除,完成插入 | |
使用共同索引不同数据的阻塞示例 | ||
13 | mysql> update test_innodb_lock set b = ‘bbbbb’ where a = 1 and b = ‘b2’;Query OK,1 row affected (0.00 sec)Rows matched: 1 Changed: 1 Warnings: 0 | |
14 | mysql> update test_innodb_lock set b = ‘bbbbb’ where a = 1 and b = ‘b1’; 被阻塞 | |
15 | mysql> commit;Query OK, 0 rows affected (0.02 sec) | |
16 | mysql> update test_innodb_lock set b = ‘bbbbb’ where a = 1 and b = ‘b1’; Query OK, 1 row affected (42.89 sec)Rows matched: 1 Changed: 1 Warnings: 0session 提交事务,阻塞去除,更新完成 | |
死锁事例 | ||
17 | mysql> update t1 set id = 110 where id = 11;Query OK, 0 rows affected (0.00 sec)Rows matched: 0 Changed: 0 Warnings: 0 | |
18 | mysql> update t2 set id = 210 where id = 21;Query OK, 1 row affected (0.00 sec)Rows matched: 1 Changed: 1 Warnings: 0 | |
19 | mysql>update t2 set id=2100 where id=21;等待sessionb释放资源,被阻塞 | |
20 | mysql>update t1 set id=1100 where id=11;Query OK,0 rows affected (0.39sec)Rows matched: 0 Changed: 0 Warnings:0等待sessiona释放资源,被阻塞 | |
两个 session 互相等等待对方的资源释放之后才能释放自己的资源,造成了死锁 |
mysql主从复制原理
主从复制实践
第一步:修改my.conf文件:
在[mysqld]段下添加:
#启用二进制日志
log-bin=mysql-bin
#服务器唯一ID,一般取IP最后一段
server-id=133
第二步:重启mysql服务
service mysqld restart
第三步:建立帐户并授权slave
mysql>GRANT FILE ON . TO ‘backup’@’%’ IDENTIFIED BY ‘123456’;
mysql>GRANT REPLICATION SLAVE, REPLICATION CLIENT ON . to ‘backup’@’%’ identified by ‘123456’;
#一般不用root帐号,“%”表示所有客户端都可能连,只要帐号,密码正确,此处可用具体客户端IP代替,如192.168.145.226,加强安全。
刷新权限
mysql> FLUSH PRIVILEGES;
查看mysql现在有哪些用户
mysql>select user,host from mysql.user;
查询master的状态
mysql> show master status;
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
| mysql-bin.000001 | 120 | db1 | mysql | |
从服务器配置
注意语句中间不要断开,master_port为mysql服务器端口号(无引号),master_user为执行同步操作的数据库账户,“120”无单引号(此处的120就是show master status 中看到的position的值,这里的mysql-bin.000001就是file对应的值)。
Slave_IO_Running: Yes //此状态必须YES
Slave_SQL_Running: Yes //此状态必须YES
注:Slave_IO及Slave_SQL进程必须正常运行,即YES状态,否则都是错误的状态
MySQL-Proxy下载
MySQL-Proxy安装
MySQL-Proxy配置
MySQL-Proxy启动域测试
mysql-proxy --defaults-file=mysql-proxy.cnf配置文件的地址
注意事项:如果没有配置profile文件的环境变量,则需要去拥有mysql- proxy命令的目录通过./mysql-proxy进行启动。
mycat是什么
MyCAT的目标是:低成本的将现有的单机数据库和应用平滑迁移到“云”端,解决数据存储和业务规模迅速增长情况下的数据瓶颈问题。
MyCAT的关键特性
如图所示:MyCAT使用Mysql的通讯协议模拟成了一个Mysql服务器,并建立了完整的Schema(数据库)、Table (数据表)、User(用户)的逻辑模型,并将这套逻辑模型映射到后端的存储节点DataNode(MySQL Instance)上的真实物理库中,这样一来,所有能使用Mysql的客户端以及编程语言都能将MyCAT当成是Mysql Server来使用,不必开发新的客户端协议。
Mycat的下载及安装
下载mycat
github地址
https://github.com/MyCATApache
Mycat安装
第一步:把MyCat的压缩包上传到linux服务器
第二步:解压缩,得到mycat目录
第三步:进入mycat/bin,启动MyCat
启动命令:./mycat start
停止命令:./mycat stop
重启命令:./mycat restart
注意:可以使用mysql的客户端直接连接mycat服务。默认服务端口为8066
Schema.xml作为MyCat中重要的配置文件之一,管理着MyCat的逻辑库、表、分片规则、DataNode以及DataSource。弄懂这些配置,是正确使用MyCat的前提。这里就一层层对该文件进行解析。
schema 标签用于定义MyCat实例中的逻辑库
Table 标签定义了MyCat中的逻辑表
dataNode 标签定义了MyCat中的数据节点,也就是我们通常说所的数据分片。
dataHost标签在mycat逻辑库中也是作为最底层的标签存在,直接定义了具体的数据库实例、读写分离配置和心跳语句。
select user()
select user()
配置rule.xml
rule.xml里面就定义了我们对表进行拆分所涉及到的规则定义。我们可以灵活的对表使用不同的分片算法,或者对表使用相同的算法但具体的参数不同。这个文件里面主要有tableRule和function这两个标签。在具体使用过程中可以按照需求添加tableRule
和function。
此配置文件可以不用修改,使用默认即可。
分片测试
Mycat读写分离和自动切换机制,需要mysql的主从复制机制配合。
Balance参数设置:
WriteType参数设置:
8.分库分表所带来的问题
通过业务分析,将不同库的join查询拆分成多个select
建立全局表(每个库都有一个相同的表)
冗余字段(不符合数据库三范式)
E-R分片(将有关系的记录都存储到一个库中)
最多支持跨两张表跨库的join
分布式事务(弱事务)
强一致性事务(同步)
最终一致性事务(异步思想)
分布式主键
redis incr命令
数据库(生成主键)
UUID