MySQL 5.6新特性MRR

一、什么是MRR 
MMR全称是Multi-Range Read,是MYSQL5.6优化器的一个新特性,在MariaDB5.5也有这个特性。优化的功能在使用二级索引做范围扫描的过程中减少磁盘随机IO和减少主键索引的访问次数。将随机IO转换为顺序IO

二、MRR和没有MRR的区别 

给出一个简单的例子,在innodb表执行下面的查询:

SELECT non_key_column FROM tbl WHERE key_column=x
在没有MRR的情况下,它是这样得到结果的:

1.  select key_column, pk_column from tb where key_column=x order  by key_column —> 假设这个结果集是t
2.  for each row in t ;   select non_key_column from tb where pk_column = pk_column_value。(在oracle里第2步叫回表)
在有MRR的情况下,它是这样执行的:
1.  select key_column, pk_column from tb where key_column = x  order by key_column —> 假设这个结果集是t
2.  将结果集t放在buffer里面(直到buffer满了),然后对结果集t按照pk_column排序      —> 假设排序好的结果集是t_sort
3.  select non_key_column fromtb where pk_column in (select pk_column from t_sort)
两者的区别主要是两点:

1. 没有MRR的情况下,随机IO增加,因为从二级索引里面得到的索引元组是有序,但是他们在主键索引里面却是无序的,所以每次去主键索引里面得到non_key_column的时候都是随机IO。(如果索引覆盖,那也就没必要利用MRR的特性了,直接从索引里面得到所有数据)

2. 没有MRR的情况下,访问主键索引的次数增加。没有MRR的情况下,二级索引里面得到多少行,那么就要去访问多少次主键索引(也不能完全这样说,因为mysql实现了BNL),而有了MRR的时候,次数就大约减少为之前次数t/buffer_size。

https://blog.csdn.net/liang_0609/article/details/44040357
https://dev.mysql.com/doc/refman/8.0/en/mrr-optimization.html
http://www.percona.com/blog/2012/03/21/multi-range-read-mrr-in-mysql-5-6-and-mariadb-5-5/

When MRR is used, the Extra column in EXPLAIN output shows Using MRR.

参考阅读:
MYSQL之ICP、MRR、BKA(推荐)

MySQL中select中的for update 使用说明(原创)

有时候我们会看到一些select语句后面紧跟一句for update,表示加锁的意思,这里我们就介绍一下对for update的理解。对于另一种手动加锁
lock in share mode 的区别见:https://blog.csdn.net/liangzhonglin/article/details/65438777

for update是一个排它锁,也就是说对于select … for update 这条语句所在的事务中可以进行任何操作(锁定的是记录,这里指主键id=1的这条记录),但其它事务中只能读取(对这条id=1的记录),不能进行update更新操作。
一般用在并发场景,如双11的时候。

为了更加方便理解,我们举例说明

事务A:

start transaction;
select * from tb where id=1 for update;
update tb set name='xyz' where id=1;

此时另一个事务B:

start transaction;
// 如果下面这条select语句也加上for update的话,此时会被阻塞,直到事务A提交或者回滚
select * from tb where id=1; 
// 下面的sql语句会被阻塞,直到事务A进行提交或者回滚
update tb set name='123' where id=1;

这里id为表的主键。为行锁,对于其它主键值非1的不存在这种情况,只要两个事务操作的不是同一条记录就可以正常运行。

推荐阅读:https://blog.csdn.net/u011957758/article/details/75212222

mysql explain 中key_len的计算方法

建议先阅读丁奇的文章:http://hidba.org/?p=404

下面我们只对其中提到的

(1).索引字段的附加信息:可以分为变长和定长数据类型讨论,当索引字段为定长数据类型,比如charintdatetime,需要有是否为空的标记,这个标记需要占用1个字节;对于变长数据类型,比如:varchar,除了是否为空的标记外,还需要有长度信息,需要占用2个字节;

(备注:当字段定义为非空的时候,是否为空的标记将不占用字节)

(2).同时还需要考虑表所使用的字符集,不同的字符集,gbk编码的为一个字符2个字节,utf8编码的一个字符3个字节;

做一个验证。

下面我们以定长数据类型准,变长数据类型请自行测试。

一、数据索引类型允许为null的情况:

表结构:

CREATE TABLE `tb` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`sid` smallint(5) DEFAULT NULL,
`gid` smallint(5) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_common` (`sid`,`gid`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

执行分析语句:

mysql> EXPLAIN select * from tb where sid=1 and gid=5;
+----+-------------+-------+------------+------+---------------+------------+---------+-------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key        | key_len | ref         | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------------+---------+-------------+------+----------+-------------+
|  1 | SIMPLE      | tb    | NULL       | ref  | idx_common    | idx_common | 6       | const,const |    1 |   100.00 | Using index |
+----+-------------+-------+------------+------+---------------+------------+---------+-------------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

发现用到了复合索引idx_common,这时复合索引的两个字段全部用到了,而由于 smallint 数据类型占用字节为两个字节, 属于定长类型,且允许为null,所以key_len长度计算公式为 (2 + 1) + (2 + 1) = 6
下面我们将两个字段全部禁止null看一下计算值

二、数据索引类型不允许为null的情况
表结构

CREATE TABLE `tb` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`sid` smallint(5) NOT NULL,
`gid` smallint(5) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_common` (`sid`,`gid`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
mysql> EXPLAIN select * from tb where sid=1 and gid=5;
+----+-------------+-------+------------+------+---------------+------------+---------+-------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key        | key_len | ref         | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------------+---------+-------------+------+----------+-------------+
|  1 | SIMPLE      | tb    | NULL       | ref  | idx_common    | idx_common | 4       | const,const |    1 |   100.00 | Using index |
+----+-------------+-------+------------+------+---------------+------------+---------+-------------+------+----------+-------------+

可以看到key_len的长度为4,即2 + 2 = 4

这里同样是复合索引中的字段全部用到,我们可以先测试一下用到一个字段的情况,依据左前缀索引原则

mysql> EXPLAIN select * from tb where sid=1;
+----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key        | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | tb    | NULL       | ref  | idx_common    | idx_common | 2       | const |    2 |   100.00 | Using index |
+----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------------+

发现key_len的值为2,就是说明只用到了一个复合索引字段,这里指的是sid字段。

Unix系统中常用的信号含义

编号为1 ~ 31的信号为传统UNIX支持的信号,是不可靠信号(非实时的),编号为32 ~ 63的信号是后来扩充的,称做可靠信号(实时信号)。不可靠信号和可靠信号的区别在于前者不支持排队,可能会造成信号丢失,而后者不会。

下面我们对编号小于SIGRTMIN的信号进行讨论。

1~15号信号为常用信号 

1) SIGHUP
本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联。
登录Linux时,系统会分配给登录用户一个终端(Session)。在这个终端运行的所有程序,包括前台进程组和后台进程组,一般都属于这个Session。当用户退出Linux登录时,前台进程组和后台有对终端输出的进程将会收到SIGHUP信号。这个信号的默认操作为终止进程,因此前台进程组和后台有终端输出的进程就会中止。不过可以捕获这个信号,比如wget能捕获SIGHUP信号,并忽略它,这样就算退出了Linux登录,wget也能继续下载。
此外,对于与终端脱离关系的守护进程,这个信号用于通知它重新读取配置文件。
2) SIGINT
程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程。
3) SIGQUIT
和SIGINT类似, 但由QUIT字符(通常是Ctrl-\)来控制.
Continue reading

Redis单线程架构

1 单线程模型

Redis客户端对服务端的每次调用都经历了发送命令,执行命令,返回结果三个过程。其中执行命令阶段,由于Redis是单线程来处理命令的,所有每一条到达服务端的命令不会立刻执行,所有的命令都会进入一个队列中,然后逐个被执行。并且多个客户端发送的命令的执行顺序是不确定的。但是可以确定的是不会有两条命令被同时执行,不会产生并发问题,这就是Redis的单线程基本模型。

2 单线程模型每秒万级别处理能力的原因

(1)纯内存访问。数据存放在内存中,内存的响应时间大约是100纳秒,这是Redis每秒万亿级别访问的重要基础。

(2)非阻塞I/O,Redis采用epoll做为I/O多路复用技术的实现,再加上Redis自身的事件处理模型将epoll中的连接,读写,关闭都转换为了时间,不在I/O上浪费过多的时间。

(3)单线程避免了线程切换和竞态产生的消耗。

(4)Redis采用单线程模型,每条命令执行如果占用大量时间,会造成其他线程阻塞,对于Redis这种高性能服务是致命的,所以Redis是面向高速执行的数据库。

redis为什么要设计成单线程:https://hacpai.com/article/1470967571415

10分钟让你明白MySQL是如何利用索引的

一、前言

在MySQL中进行SQL优化的时候,经常会在一些情况下,对MySQL能否利用索引有一些迷惑。

譬如:

  1. MySQL 在遇到范围查询条件的时候就停止匹配了,那么到底是哪些范围条件?
  2. MySQL 在LIKE进行模糊匹配的时候又是如何利用索引的呢?
  3. MySQL 到底在怎么样的情况下能够利用索引进行排序?

请见:http://www.fordba.com/spend-10-min-to-understand-how-mysql-use-index.html