WSL

Make it started when you start your Windows

wsl-ubuntun.vbs - 开机自启

1
2
Set ws = CreateObject("Wscript.Shell")
ws.run "C:\Users\guo\AppData\Local\Microsoft\WindowsApps\ubuntu1804.exe run sudo /etc/init.wsl", vbhide

/etc/init.wsl

1
2
3
4
#! /bin/sh
/etc/init.d/ssh restart
/etc/init.d/mysql restart
/etc/init.d/cron restart
1
2
3
4
5
6
7
sudo chmod a+w "R"

# 递归查找视频文件并移动,指定遍历最小深度为 2, 当前目录忽略
find . -mindepth 2 -type f | grep -ZP "\.(MP4|mkv|mov|mp4|wmv)$" | awk '{ printf $0"\0" }' | xargs -I R -0 -n 1 sudo mv "R" video/

# 递归查找图片文件并移动,指定遍历最小深度为 2, 当前目录忽略
find . -mindepth 2 -type f | grep -P "\.(JPG|jpg|png|jpeg|gif|raw)$" | awk '{ printf $0"\0" }' | xargs -I R -0 -n 1 sudo mv "R" ./picture

Thread 线程

Java 中的线程

Thread 类与 Runnable 接口

Thread 中部分方法:

  • join():调用 join() 方法的 Thread 对象结束以前,当前线程一直处于等待状态,不会继续向前运行;内部是通过循环判断该 Thread 对象的 isAlive 方法返回 true 时,调用该 Thread 对象的 wait() 方法,该方法是属于 Object 的方法,且是由当前线程进行调用的,因此当前线程会处于等待状态;当调用 join() 方法的 Thread 对象结束后,会调用 notifyAll 方法通知处于等待状态的线程
1
2
3
4
5
6
7
8
9
10
11
12
public static void joinTest() {
for (int i = 0; i < 10; i++) {
int finalI = i;
final Thread thread = new Thread(() -> System.out.println(finalI));
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

输出: 0,1,2,3,4,5,6,7,8,9

  • setDaemon(): 线程的默认行为是,只要线程活着,进程就无法退出(普通的用户线程),守护线程不会阻止进程的退出;当应用程序的所有非守护线程均已经结束时,无论是否存在正在运行的守护线程,Java 程序将结束
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void daemonTest() {
final Thread thread = new Thread(() -> {
while (true) {
System.out.println("true = " + true);
}
});
thread.setName("local-daemon-thread-20200204");
thread.setDaemon(true);
thread.start();

// 只要主线程的打印执行完毕,不管守护线程有没有在执行,整个执行都将结束
for (int i = 0; i < 100; i++) {
System.out.println("main thread = " + i);
}
}
  • setUncaughtExceptionHandler():线程因异常而退出时,默认的行为是打印线程的名称,异常类型,异常消息、堆栈打印;可以设置一个未捕获异常的处理器
1
2
3
4
5
6
7
8
9
public static void exceptionHandlerTest() {
final Thread thread = new Thread(() -> {
throw new IllegalArgumentException("illegal argument");
});
thread.setUncaughtExceptionHandler((t, e) -> {
System.out.printf("thread id: %s, thread name: %s, exception: %s", t.getId(), t.getName(), e);
});
thread.start();
}

多个 Thread 使用一个 Runnable 对象与每个 Thread 使用独立的 Runnable 对象的区别?

Mybatis

事务的隔离级别

RowBounds, 所以在这方面,不同的驱动能够取得不同级别的高效率。为了取得最佳的表现,请使用结果集的 SCROLL_SENSITIVE 或 SCROLL_INSENSITIVE 的类型(换句话说:不用 FORWARD_ONLY)。

很多时候你不用调用 rollback(),因为 MyBatis 会在你没有调用 commit 时替你完成回滚操作。然而,如果你需要在支持多提交和回滚的 session 中获得更多细粒度控制,你可以使用回滚操作来达到目的。

默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。

每当一个新 session 被创建,MyBatis 就会创建一个与之相关联的本地缓存。任何在 session 执行过的查询语句本身都会被保存在本地缓存中,那么,相同的查询语句和相同的参数所产生的更改就不会二度影响数据库了。本地缓存会被增删改、提交事务、关闭事务以及关闭 session 所清空。

  • 是否意味着,同一个session的相同多次查询,总是会从本地缓存中读取数据?如果有人直接修改了数据库,session感知不到?
  • 无论是本地的会话缓存,还是全局二级缓存,是否都存在上述情况?

<association> 相似,而 many 属性是对集合而言的,和<collection>

resultType 从这条语句中返回的期望类型的类的完全限定名或别名。 ==注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身==。可以使用 resultType 或 resultMap,但不能同时使用。

@Param 参数 N/A 如果你的映射方法的形参有多个,这个注解使用在映射方法的参数上就能为它们取自定义名字。若不给出自定义名字,多参数(不包括 RowBounds 参数)则先以 “param” 作前缀,再加上它们的参数位置作为参数别名。例如 #{param1}, #{param2},这个是默认值。如果注解是 @Param(“person”),那么参数就会被命名为 #{person}。

需要试验一下,映射方法有多个参数

如何通过 Java 代码添加 Sql 映射文件

  1. 通过 configuration 对象添加了一个映射器类。映射器类是 Java 类,它们包含 SQL 映射语句的注解从而避免依赖 XML 文件。如果没有包含注解,并且存在一个同名的 XML 映射文件, Mybatis 会自动查找并加载它,BlogMapper.class 对应会加载 BlogMapper.xml
1
configuration.addMapper(BlogMapper.class);
  1. 也可以根据 mybatis 内部 configuration 对象如何解析对应的 Sql 映射文件来自己实现添加对应的 sql 映射文件,而不必通过配置文件的 mapper 标签来添加。

MRR and BAK Algorithm

1 Multi-Range Read Optimization 多范围索引扫描读优化

在次级索引上使用范围扫描(range scan)读取行时,当表很大且没有存储再存储引擎的缓存中时,就可能会导致对基础表的的许多磁盘的随机访问。 Mysql 试图通过 Multi-Range Read (MRR) 优化来减少范围扫描时的随机磁盘访问

步骤:

  1. 首先只扫描索引。并收集相关行的键(keys for the relevent rows)
  2. 对这些键进行排序,使用键排序的顺序访基表检索数据行

优化的动机就是减少随机磁盘访问,实现对基表的更多的顺序扫描

优点:

  1. MRR 基于索引对,使得数据行的访问是顺序执行的,而不是随机的。Server 获取满足查询条件的索引对 (index tuple),根据数据行键(row ID)进行排序,使用排序的结果顺序访问完整的数据行。使得数据访问更高效,较低磁盘IO消耗
  2. MRR 允许批量处理对键访问的请求,这些请求用于需要通过索引对访问数据行的操作,比如范围索引扫描和使用索引连接属性的等值连接。MRR 迭代索引范围序列,获得满足条件的索引对。将这些结果进行聚合,访问对应的数据行。并且没有获取所有的索引对后才进行数据行的读取

MRR 不支持虚拟列上的次级索引.

哪些场景下可以利用 MRR 优化:

  • 场景 A

    InnoDB, MyISAM 表的索引范围扫描或者等值连接操作 (equi-join operations)

    1. 部分索引对被存储 (accumulated) 在缓存区中
    2. 缓冲区中的索引对通过数据行ID进行排序
    3. 根据排序的索引对的顺序访问数据行
  • 场景 B

    MRR 可以用于 NDB 表,用于多范围索引扫描,或者用于通过属性执行等值连接。

    1. 部分范围(可能是单键范围)缓存在查询提交的中心节点上的缓冲区中 (A portion of ranges, possibly single-key ranges, is accumulated in a buffer on the central node
      where the query is submitted)
    2. 这些范围查询被发送到执行节点来访问数据
    3. 数据行被打包发送回中心节点
    4. 将接收到的包 (带有数据行) 存放在缓冲区中
    5. 从缓冲区中返回结果行

如何判断当前查询使用了 MRR 优化

执行计划的 Extra 列为 Using MRR

InnoDB, MyISAM 如果需要进行全表扫描时, 不会使用 MRR 优化. 例如: 如果仅仅基于索引对中的信息就可以获取查询结构, 即 覆盖索引, MRR 不会提供任何优化.

如何开启 MRR

optimizer_switch 系统变量提供了使用 MRR 优化的开关, mrr 标志表示 MRR 是否已开启 (on), 默认开启, mrr_cost_based 标志表示控制查询优化器是否尝试基于性能的选择, 使用或不适用 MRR, 默认开启 (on). 如果希望尽可能的使用 MRR , 将其置为 off

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
SELECT @@optimizer_switch;

index_merge=on,
index_merge_union=on,
index_merge_sort_union=on,
index_merge_intersection=on,
engine_condition_pushdown=on,
index_condition_pushdown=on,
mrr=on,
mrr_cost_based=on,
block_nested_loop=on,
batched_key_access=off,
materialization=on,
semijoin=on,
loosescan=on,
firstmatch=on,
duplicateweedout=on,
subquery_materialization_cost_based=on,
use_index_extensions=on,
condition_fanout_filter=on,
derived_merge=on

read_rnd_buffer_size 系统变量表明可以为缓冲区分配的内存字节大小.

1
2
3
4
-- 默认 262144B = 256KB
SELECT @@read_rnd_buffer_size /1024;

256.0000

示例

1
2
3
4
5
6
7
8
9
10
show create table user_info;

CREATE TABLE `user_info` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uid` varchar(64) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`upd_time` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `user_info_uid_index` (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=22000001 DEFAULT CHARSET=utf8

使用 in 的范围查询

1
2
3
4
5
6
7
8
9
explain select * from user_info where uid in ('204-42-7061','735-14-7777','321-09-5846');


+----+-------------+-----------+------------+-------+---------------------+---------------------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------------+---------------------+---------+------+------+----------+-----------------------+
| 1 | SIMPLE | user_info | NULL | range | user_info_uid_index | user_info_uid_index | 194 | NULL | 3 | 100.00 | Using index condition |
+----+-------------+-----------+------------+-------+---------------------+---------------------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

image-20200705144752910

1
2
3
4
5
6
7
8
9
-- in 的条件查询有 400 多个,后面的省略了
explain select * from user_info where uid in ('204-42-7061','735-14-7777','321-09-5846','736-50-3975','176-55-0702','466-84-4864','157-95-0925','358-76-6422','275-11-5932','316-90-4137','868-03-2935','020-06-6077','726-08-5008','475-65-1649','059-97-0370','503-92-8111','385-02-6790','451-49-1154','020-16-2354','588-93-7398','657-12-6885','155-98-3036','838-63-2477','780-33-4522','033-70-3319','529-49-3149','006-93-6411','749-94-6620','717-17-1261','377-55-0697','525-59-2422','565-14-3063','686-91-9092','381-99-6716','228-22-7720','431-62-1403','222-46-8484','556-13-2704','053-34-8148','128-05-3170','599-38-5086','722-22-2334', ...)


+----+-------------+-----------+------------+-------+---------------------+---------------------+---------+------+------+----------+----------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------------+---------------------+---------+------+------+----------+----------------------------------+
| 1 | SIMPLE | user_info | NULL | range | user_info_uid_index | user_info_uid_index | 194 | NULL | 435 | 100.00 | Using index condition; Using MRR |
+----+-------------+-----------+------------+-------+---------------------+---------------------+---------+------+------+----------+----------------------------------+

image-20200705145000247

2 Block Nested-Loop and Batched Key Access Joins

MySQL 中可以使用 Batched Key Access (BKA) 连接算法来同时使用索引来访问被连接的表, 同样也使用一个连接缓冲区. BKA 算法支持内连接, 外连接, 以及半连接 (semijoin operations), 包括前内外连接. BKA 算法由于更高效的表扫描, 可以提升连接的性能. 同时, Block Nested-Loop(BNL) 连接算法也可以被扩展应用与的外连接等操作.

Join Buffer Management for Block Nested-Loop and Batched Key Access Algorithms

Block Nested-Loop Algorithm for Outer Joins and Semijoins

Batched Key Access Joins

Batched Key Access (BKA) 连接算法用于连接表, 当第二个连接操作数( the second join operand - 被驱动表) 表生成的行可以使用索引访问时, 可以使用应用 BKA 算法.

  1. 和 BNL 算法一样, BKA 连接算法会使用一个连接缓冲区 (join buffer) 来缓存连接操作中驱动表行的感兴趣的列.
  2. 然后 BKA 算法会构建缓冲区中所有行的键 (keys 索引) 来访问被连接的表
  3. 以批量的方式将这些 keys 提交给数据库引擎进行索引查询
  4. 提交的 keys 通过 MRR 接口进行处理, 以优化的方式, 使用索引进行查询
  5. 获取由这些 keys 匹配的行, 返回给 BKA 连接算法, 每一个匹配的行同时带了一个指向连接缓冲区中行的引用

使用 BKA 时, join_buffer_size 定义的时每次发给存储引擎的批量 keys 的大小

开启 BKA

optimizer_switch 系统变量的 batched_key_access 需要置为 on, BKA 同时使用 MRR, mrr 也需要置为 on. 并且由于目前对于使用 MRR 所进行的优化效果过于悲观, 需要将 mrr_cost_based 置为 off

1
SET optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';

如何判断当前连接查询使用了 BKA 算法

执行计划的 Extra 列为 Using join buffer (Batched Key Access), 同时, 连接类型 typeref 或者 eq_ref

MRR 的执行由由两种场景

  • 传统的基于磁盘的存储引擎, 如 InnoDB 和 MyISAM, 对于这些引擎. 来自连接缓冲区的所有行的键一次性提交给 MRR. 特定于引擎的 MRR 函数对提交的键进行索引查找, 从他们中获取行 id (或主键), 然后获取所有行 id 对应的行数据. 返回的每一行都带了一个关联引用 (用于访问连接缓冲区中的行). MRR 读取行时使用了行 id的顺序进行读取 (顺序访问而不是随机访问).
  • 远程存储引擎, 如 NDB, MySQL Server (SQL 节点)将连接缓冲区的部分行的键及其关联引用发送到 NDB 集群的数据节点. SQL 节点收到数据节点返回的包(一个或多个), 其中包含了匹配的行以及相应的关联引用. BKA 算法利用这些行并构建新的连接行. 然后想数据节点发送行的键, 知道所有的连接操作匹配已经完成.

示例

开启 BKA

1
SET optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';
1
2
3
4
5
6
7
8
show create table user_score;

CREATE TABLE `user_score` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uid` varchar(64) NOT NULL,
`score` float DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8

连接查询, 并且被驱动表的连接类型是 ref, eq_ref

1
2
3
4
5
6
7
8
explain select * from user_score a left join  user_info b on a.uid = b.uid;

+----+-------------+-------+------------+------+---------------------+---------------------+---------+-------------------+------+----------+----------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------------+---------------------+---------+-------------------+------+----------+----------------------------------------+
| 1 | SIMPLE | a | NULL | ALL | NULL | NULL | NULL | NULL | 6 | 100.00 | NULL |
| 1 | SIMPLE | b | NULL | ref | user_info_uid_index | user_info_uid_index | 194 | learning_db.a.uid | 1 | 100.00 | Using join buffer (Batched Key Access) |
+----+-------------+-------+------------+------+---------------------+---------------------+---------+-------------------+------+----------+----------------------------------------+

image-20200705152742898

关掉 BKA, 还原默认设置

1
2
3
SET optimizer_switch='mrr=on,mrr_cost_based=on,batched_key_access=off';

explain select * from user_score a left join user_info b on a.uid = b.uid;

image-20200705154158520

*被驱动表的连接类型不是 ref, eq_ref *

1
2
3
4
5
6
7
8
explain select * from user_info a left join user_score b on a.uid = b.uid;

+----+-------------+-------+------------+------+---------------+------+---------+------+----------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+----------+----------+----------------------------------------------------+
| 1 | SIMPLE | a | NULL | ALL | NULL | NULL | NULL | NULL | 21919807 | 100.00 | NULL |
| 1 | SIMPLE | b | NULL | ALL | NULL | NULL | NULL | NULL | 6 | 100.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+----------+----------+----------------------------------------------------+

image-20200705153949927