## 模块 2: 使用 TiKV MVCC 内存引擎

在本模块中，参与者首先会创建 6 张表，其中每 2 张表基于之前定义的 PLACEMENT POLICY 将 LEADER 角色的 Region 数据放在同一个 TiKV 节点上。同一个 TiKV 节点上的两张表一张表含有较多的 MVCC 历史快照数据，而另一张表几乎不含有 MVCC 历史数据。这三个 TiKV 节点对于 TiKV MVCC 内存引擎的配置各不相同，参与者会分别对这 6 张表进行扫描，并观察不同配置的 TiKV MVCC 内存引擎的表现。同时，参与者会修改 TiKV MVCC 内存引擎的配置并观察修改配置后的现象。

### 步骤 1. 用四个终端连接到 TiUP 控制机器

+ 通过点击以下链接打开四个 SSH 连接到你的实验虚拟机：
  + [终端 1](ssh://monitor1-ssh#1)
  + [终端 2](ssh://monitor1-ssh#2)
  + [终端 3](ssh://monitor1-ssh#3)
  + [终端 4](ssh://monitor1-ssh#4)

+ 现在你将有四个活动的终端会话。

### 步骤 2. 创建表

+ 在[终端 1](ssh://monitor1-ssh#1) 上，连接到 TiDB 服务器实例。

  ```bash
  mysql -h ${HOST_DB1_PRIVATE_IP} --port 4000 -u root
  ```

  ```output
  mysql> 
  ```

+ 在[终端 1](ssh://monitor1-ssh#1) 上，创建 `test` 下的表 `tbl_no_ime_R1`，`tbl_ime_R1`，`tbl_no_ime_R2`，`tbl_ime_R2`，`tbl_no_ime_R3` 和 `tbl_ime_R3`，并了解创建表所用的 DDL 语句。

  ```sql
  DROP TABLE IF EXISTS test.tbl_no_ime_R1;
  CREATE TABLE test.tbl_no_ime_R1 (
  `ID` bigint (20) NOT NULL AUTO_INCREMENT,
  `pID` bigint (20) NOT NULL,
  `cID` bigint (20) NOT NULL,
  `sID` bigint (20) NOT NULL,
  `pState` varchar (100) NOT NULL,
  `cState` tinyint (4) DEFAULT NULL,
  `created_at` DATETIME,
  `updated_at` DATETIME,
  `txt` varchar(64) DEFAULT 'IMETEST',
  PRIMARY KEY (`sID`, `ID`),
  UNIQUE KEY `pcsID` (`pID`, `cID`, `sID`),
  KEY `pcStateIndex` (`pState`, `cState`)
  ) PLACEMENT POLICY = IME_R1;

  DROP TABLE IF EXISTS test.tbl_ime_R1;
  CREATE TABLE test.tbl_ime_R1 (
  `ID` bigint (20) NOT NULL AUTO_INCREMENT,
  `pID` bigint (20) NOT NULL,
  `cID` bigint (20) NOT NULL,
  `sID` bigint (20) NOT NULL,
  `pState` varchar (100) NOT NULL,
  `cState` tinyint (4) DEFAULT NULL,
  `created_at` DATETIME,
  `updated_at` DATETIME,
  `txt` varchar(64) DEFAULT 'IMETEST',
  PRIMARY KEY (`sID`, `ID`),
  UNIQUE KEY `pcsID` (`pID`, `cID`, `sID`),
  KEY `pcStateIndex` (`pState`, `cState`)
  ) PLACEMENT POLICY = IME_R1;

  DROP TABLE IF EXISTS test.tbl_no_ime_R2;
  CREATE TABLE test.tbl_no_ime_R2 (
  `ID` bigint (20) NOT NULL AUTO_INCREMENT,
  `pID` bigint (20) NOT NULL,
  `cID` bigint (20) NOT NULL,
  `sID` bigint (20) NOT NULL,
  `pState` varchar (100) NOT NULL,
  `cState` tinyint (4) DEFAULT NULL,
  `created_at` DATETIME,
  `updated_at` DATETIME,
  `txt` varchar(64) DEFAULT 'IMETEST',
  PRIMARY KEY (`sID`, `ID`),
  UNIQUE KEY `pcsID` (`pID`, `cID`, `sID`),
  KEY `pcStateIndex` (`pState`, `cState`)
  ) PLACEMENT POLICY = IME_R2;

  DROP TABLE IF EXISTS test.tbl_ime_R2;
  CREATE TABLE test.tbl_ime_R2 (
  `ID` bigint (20) NOT NULL AUTO_INCREMENT,
  `pID` bigint (20) NOT NULL,
  `cID` bigint (20) NOT NULL,
  `sID` bigint (20) NOT NULL,
  `pState` varchar (100) NOT NULL,
  `cState` tinyint (4) DEFAULT NULL,
  `created_at` DATETIME,
  `updated_at` DATETIME,
  `txt` varchar(64) DEFAULT 'IMETEST',
  PRIMARY KEY (`sID`, `ID`),
  UNIQUE KEY `pcsID` (`pID`, `cID`, `sID`),
  KEY `pcStateIndex` (`pState`, `cState`)
  ) PLACEMENT POLICY = IME_R2;

  DROP TABLE IF EXISTS test.tbl_no_ime_R3;
  CREATE TABLE test.tbl_no_ime_R3 (
  `ID` bigint (20) NOT NULL AUTO_INCREMENT,
  `pID` bigint (20) NOT NULL,
  `cID` bigint (20) NOT NULL,
  `sID` bigint (20) NOT NULL,
  `pState` varchar (100) NOT NULL,
  `cState` tinyint (4) DEFAULT NULL,
  `created_at` DATETIME,
  `updated_at` DATETIME,
  `txt` varchar(64) DEFAULT 'IMETEST',
  PRIMARY KEY (`sID`, `ID`),
  UNIQUE KEY `pcsID` (`pID`, `cID`, `sID`),
  KEY `pcStateIndex` (`pState`, `cState`)
  ) PLACEMENT POLICY = IME_R3;

  DROP TABLE IF EXISTS test.tbl_ime_R3;
  CREATE TABLE test.tbl_ime_R3 (
  `ID` bigint (20) NOT NULL AUTO_INCREMENT,
  `pID` bigint (20) NOT NULL,
  `cID` bigint (20) NOT NULL,
  `sID` bigint (20) NOT NULL,
  `pState` varchar (100) NOT NULL,
  `cState` tinyint (4) DEFAULT NULL,
  `created_at` DATETIME,
  `updated_at` DATETIME,
  `txt` varchar(64) DEFAULT 'IMETEST',
  PRIMARY KEY (`sID`, `ID`),
  UNIQUE KEY `pcsID` (`pID`, `cID`, `sID`),
  KEY `pcStateIndex` (`pState`, `cState`)
  ) PLACEMENT POLICY = IME_R3;

  EXIT;
  ```

  ```output
  mysql>   DROP TABLE IF EXISTS test.tbl_no_ime_R1;
  Query OK, 0 rows affected, 1 warning (0.00 sec)

  mysql>   CREATE TABLE test.tbl_no_ime_R1 (
      ->   `ID` bigint (20) NOT NULL AUTO_INCREMENT,
      ->   `pID` bigint (20) NOT NULL,
      ->   `cID` bigint (20) NOT NULL,
      ->   `sID` bigint (20) NOT NULL,
      ->   `pState` varchar (100) NOT NULL,
      ->   `cState` tinyint (4) DEFAULT NULL,
      ->   `created_at` DATETIME,
      ->   `updated_at` DATETIME,
      ->   `txt` varchar(64) DEFAULT 'IMETEST',
      ->   PRIMARY KEY (`sID`, `ID`),
      ->   UNIQUE KEY `pcsID` (`pID`, `cID`, `sID`),
      ->   KEY `pcStateIndex` (`pState`, `cState`)
      ->   ) PLACEMENT POLICY = IME_R1;
  Query OK, 0 rows affected, 5 warnings (0.10 sec)

  ...

  mysql> 
  mysql>   DROP TABLE IF EXISTS test.tbl_ime_R3;
  Query OK, 0 rows affected, 1 warning (0.00 sec)

  mysql>   CREATE TABLE test.tbl_ime_R3 (
      ->   `ID` bigint (20) NOT NULL AUTO_INCREMENT,
      ->   `pID` bigint (20) NOT NULL,
      ->   `cID` bigint (20) NOT NULL,
      ->   `sID` bigint (20) NOT NULL,
      ->   `pState` varchar (100) NOT NULL,
      ->   `cState` tinyint (4) DEFAULT NULL,
      ->   `created_at` DATETIME,
      ->   `updated_at` DATETIME,
      ->   `txt` varchar(64) DEFAULT 'IMETEST',
      ->   PRIMARY KEY (`sID`, `ID`),
      ->   UNIQUE KEY `pcsID` (`pID`, `cID`, `sID`),
      ->   KEY `pcStateIndex` (`pState`, `cState`)
      ->   ) PLACEMENT POLICY = IME_R3;
  Query OK, 0 rows affected, 5 warnings (0.07 sec)

  mysql> 
  mysql>   EXIT;
  Bye
  ```

+ 通过创建表的 DDL 语句中对于 PLACEMENT POLICY 的定义，可以了解到：
  + 表 `tbl_no_ime_R1` 和 `tbl_ime_R1` 的 PLACEMENT POLICY 为 `IME_R1`，表示它们所有的 LEADER 角色 Region 都存储在 `region1` 的 TiKV 节点上，对其进行的读写默认也在 `region1` 的 TiKV 节点上。
  + 表 `tbl_no_ime_R2` 和 `tbl_ime_R2` 的 PLACEMENT POLICY 为 `IME_R2`，表示它们所有的 LEADER 角色 Region 都存储在 `region2` 的 TiKV 节点上，对其进行的读写默认也在 `region2` 的 TiKV 节点上。
  + 表 `tbl_no_ime_R3` 和 `tbl_ime_R3` 的 PLACEMENT POLICY 为 `IME_R3`，表示它们所有的 LEADER 角色 Region 都存储在 `region3` 的 TiKV 节点上，对其进行的读写默认也在 `region3` 的 TiKV 节点上。
  + 表 `tbl_no_ime_R1`，`tbl_ime_R1`，`tbl_no_ime_R2`，`tbl_ime_R2`，`tbl_no_ime_R3` 和 `tbl_ime_R3` 在 TiKV 集群中的存储如下图所示：

  ![IME_PART2_TABLES_1.png 70%](https://lab-static.pingcap.com/images/2025/8/20/e8caf85c16d6ae4ba61ae26b8929dc1bceac86c4.png)

### 步骤 3. 初始化数据

+ 在[终端 1](ssh://monitor1-ssh#1) 上，使用 tiup bench 工具向表 `tbl_no_ime_R1`，`tbl_no_ime_R2` 和 `tbl_no_ime_R3` 中各插入 1,000 行随机数据。关于 TiUP bench 组件的使用请参考：<https://docs.pingcap.com/zh/tidb/stable/tiup-bench/>。

  ```bash
  cat > tbl_no_ime_R1_R2_R3.sql <<EOF
  INSERT INTO test.tbl_no_ime_R1 (pID, cID, sID, pState, cState, created_at, updated_at) VALUES (1 + FLOOR(RAND() * 99999), 100001 + FLOOR(RAND() * 99999), 200001 + FLOOR(RAND() * 99999), ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), 1 + FLOOR(RAND() * 29), NOW(), NOW());
  INSERT INTO test.tbl_no_ime_R2 (pID, cID, sID, pState, cState, created_at, updated_at) VALUES (1 + FLOOR(RAND() * 99999), 100001 + FLOOR(RAND() * 99999), 200001 + FLOOR(RAND() * 99999), ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), 1 + FLOOR(RAND() * 29), NOW(), NOW());
  INSERT INTO test.tbl_no_ime_R3 (pID, cID, sID, pState, cState, created_at, updated_at) VALUES (1 + FLOOR(RAND() * 99999), 100001 + FLOOR(RAND() * 99999), 200001 + FLOOR(RAND() * 99999), ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), 1 + FLOOR(RAND() * 29), NOW(), NOW());
  EOF
  tiup bench rawsql run -H ${HOST_DB1_PRIVATE_IP} -P 4000 --count 1000 --threads 1 --query-files tbl_no_ime_R1_R2_R3.sql
  ```

  ```output
  A new version of bench is available:  -> v1.12.0

      To update this component:   tiup update bench
      To update all components:   tiup update --all

  The component `bench` version  is not installed; downloading from repository.
  Starting component bench: /home/ec2-user/.tiup/components/bench/v1.12.0/tiup-bench rawsql run -H 10.90.1.40 -P 4000 --count 1000 --threads 1 --query-files tbl_no_ime_R1_R2_R3.sql
  Finished
  [Summary] TBL_NO_IME_R1_R2_R3: 0.01s
  ```

+ 在[终端 1](ssh://monitor1-ssh#1) 上，连接到 TiDB 服务器实例。

  ```bash
  mysql -h ${HOST_DB1_PRIVATE_IP} --port 4000 -u root
  ```

  ```output
  mysql> 
  ```

+ 在[终端 1](ssh://monitor1-ssh#1) 上，创建 3 个序列（SEQUENCE）对象，`test.seq_ime_R1`，`test.seq_ime_R2` 和 `test.seq_ime_R3`，供接下来向表 `test.tbl_ime_R1`, `test.tbl_ime_R2` 和 `test.tbl_ime_R3` 插入数据使用。

  ```sql
  DROP SEQUENCE IF EXISTS test.seq_ime_R1;
  CREATE SEQUENCE test.seq_ime_R1;
  DROP SEQUENCE IF EXISTS test.seq_ime_R2;
  CREATE SEQUENCE test.seq_ime_R2;
  DROP SEQUENCE IF EXISTS test.seq_ime_R3;
  CREATE SEQUENCE test.seq_ime_R3;
  EXIT
  ```

  ```output
  mysql> DROP SEQUENCE IF EXISTS test.seq_ime_R1;
  Query OK, 0 rows affected, 1 warning (0.00 sec)
  mysql> CREATE SEQUENCE test.seq_ime_R1;
  Query OK, 0 rows affected (0.06 sec)

  mysql> DROP SEQUENCE IF EXISTS test.seq_ime_R2;
  Query OK, 0 rows affected, 1 warning (0.00 sec)
  mysql> CREATE SEQUENCE test.seq_ime_R2;
  Query OK, 0 rows affected (0.06 sec)

  mysql> DROP SEQUENCE IF EXISTS test.seq_ime_R3;
  Query OK, 0 rows affected, 1 warning (0.00 sec)
  mysql> CREATE SEQUENCE test.seq_ime_R3;
  Query OK, 0 rows affected (0.06 sec)

  mysql> EXIT
  Bye
  ```

+ 在[终端 1](ssh://monitor1-ssh#1) 上，使用 tiup bench 工具向表 `tbl_ime_R1` 中插入 1,000 行随机数据， 与表 `tbl_no_ime_R1` 不同的是每插入一行数据后会对该行数据进行 10 次更新操作（UPDATE），即产生 10 个 MVCC 快照，大约需要 1 分钟完成。

  ```bash
  cat > tbl_ime_R1.sql <<EOF
  SELECT @sID := 200001 + FLOOR(RAND() * 99999);
  INSERT INTO test.tbl_ime_R1 (pID, cID, sID, pState, cState, created_at, updated_at) VALUES (1 + FLOOR(RAND() * 99999), 100001 + FLOOR(RAND() * 99999), @sID, ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), 1 + FLOOR(RAND() * 29), NOW(), NOW());
  SELECT @ID := NEXTVAL(test.seq_ime_R1);
  UPDATE test.tbl_ime_R1 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID;
  UPDATE test.tbl_ime_R1 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID;
  UPDATE test.tbl_ime_R1 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID;
  UPDATE test.tbl_ime_R1 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID;
  UPDATE test.tbl_ime_R1 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID;
  UPDATE test.tbl_ime_R1 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID;
  UPDATE test.tbl_ime_R1 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID;
  UPDATE test.tbl_ime_R1 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID;
  UPDATE test.tbl_ime_R1 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID;
  UPDATE test.tbl_ime_R1 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID;
  EOF
  tiup bench rawsql run -H ${HOST_DB1_PRIVATE_IP} -P 4000 --count 1000 --threads 1 --query-files tbl_ime_R1.sql
  ```

  ```output
  Starting component bench: /home/ec2-user/.tiup/components/bench/v1.12.0/tiup-bench rawsql run -H 10.90.1.40 -P 4000 --count 1000 --threads 1 --query-files tbl_ime_R1.sql
  [Current] TBL_IME_R1: 0.00s
  [Current] TBL_IME_R1: 0.00s
  [Current] TBL_IME_R1: 0.00s
  [Current] TBL_IME_R1: 0.00s
  [Current] TBL_IME_R1: 0.00s
  Finished
  [Summary] TBL_IME_R1: 0.00s
  ```

  + 在[终端 1](ssh://monitor1-ssh#1) 上，使用 tiup bench 工具向表 `tbl_ime_R2` 中插入 1,000 行随机数据， 与表 `tbl_no_ime_R2` 不同的是每插入一行数据后会对该行数据进行 10 次更新操作（UPDATE），即产生 10 个 MVCC 快照，大约需要 1 分钟完成。

  ```bash
  cat > tbl_ime_R2.sql <<EOF
  SELECT @sID := 200001 + FLOOR(RAND() * 99999);
  INSERT INTO test.tbl_ime_R2 (pID, cID, sID, pState, cState, created_at, updated_at) VALUES (1 + FLOOR(RAND() * 99999), 100001 + FLOOR(RAND() * 99999), @sID, ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), 1 + FLOOR(RAND() * 29), NOW(), NOW());
  SELECT @ID := NEXTVAL(test.seq_ime_R2);
  UPDATE test.tbl_ime_R2 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  UPDATE test.tbl_ime_R2 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  UPDATE test.tbl_ime_R2 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  UPDATE test.tbl_ime_R2 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  UPDATE test.tbl_ime_R2 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  UPDATE test.tbl_ime_R2 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  UPDATE test.tbl_ime_R2 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  UPDATE test.tbl_ime_R2 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  UPDATE test.tbl_ime_R2 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  UPDATE test.tbl_ime_R2 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  EOF
  tiup bench rawsql run -H ${HOST_DB1_PRIVATE_IP} -P 4000 --count 1000 --threads 1 --query-files tbl_ime_R2.sql
  ```

  ```output
  Starting component bench: /home/ec2-user/.tiup/components/bench/v1.12.0/tiup-bench rawsql run -H 10.90.1.40 -P 4000 --count 1000 --threads 1 --query-files tbl_ime_R2.sql
  [Current] TBL_IME_R2: 0.00s
  [Current] TBL_IME_R2: 0.00s
  [Current] TBL_IME_R2: 0.00s
  [Current] TBL_IME_R2: 0.00s
  [Current] TBL_IME_R2: 0.00s
  [Current] TBL_IME_R2: 0.00s
  Finished
  [Summary] TBL_IME_R2: 0.00s
  ```

  + 在[终端 1](ssh://monitor1-ssh#1) 上，使用 tiup bench 工具向表 `tbl_ime_R3` 中插入 1,000 行随机数据， 与表 `tbl_no_ime_R3` 不同的是每插入一行数据后会对该行数据进行 10 次更新操作（UPDATE），即产生 10 个 MVCC 快照，大约需要 1 分钟完成。

  ```bash
  cat > tbl_ime_R3.sql <<EOF
  SELECT @sID := 200001 + FLOOR(RAND() * 99999);
  INSERT INTO test.tbl_ime_R3 (pID, cID, sID, pState, cState, created_at, updated_at) VALUES (1 + FLOOR(RAND() * 99999), 100001 + FLOOR(RAND() * 99999), @sID, ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), 1 + FLOOR(RAND() * 29), NOW(), NOW());
  SELECT @ID := NEXTVAL(test.seq_ime_R3);
  UPDATE test.tbl_ime_R3 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  UPDATE test.tbl_ime_R3 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  UPDATE test.tbl_ime_R3 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  UPDATE test.tbl_ime_R3 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  UPDATE test.tbl_ime_R3 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  UPDATE test.tbl_ime_R3 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  UPDATE test.tbl_ime_R3 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  UPDATE test.tbl_ime_R3 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  UPDATE test.tbl_ime_R3 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  UPDATE test.tbl_ime_R3 SET pState = ELT(1 + FLOOR(RAND() * 9), 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's0'), cState = 1 + FLOOR(RAND() * 29) WHERE sID = @sID AND ID = @ID; 
  EOF
  tiup bench rawsql run -H ${HOST_DB1_PRIVATE_IP} -P 4000 --count 1000 --threads 1 --query-files tbl_ime_R3.sql
  ```

  ```output
  Starting component bench: /home/ec2-user/.tiup/components/bench/v1.12.0/tiup-bench rawsql run -H 10.90.1.40 -P 4000 --count 1000 --threads 1 --query-files tbl_ime_R3.sql
  [Current] TBL_IME_R3: 0.00s
  [Current] TBL_IME_R3: 0.00s
  [Current] TBL_IME_R3: 0.00s
  [Current] TBL_IME_R3: 0.00s
  [Current] TBL_IME_R3: 0.00s
  Finished
  [Summary] TBL_IME_R3: 0.00s
  ```

### 步骤 4. 检查数据的分布

+ 在[终端 1](ssh://monitor1-ssh#1) 上，连接到 TiDB 服务器实例。

  ```bash
  mysql -h ${HOST_DB1_PRIVATE_IP} --port 4000 -u root
  ```

  ```output
  mysql> 
  ```

+ 在[终端 1](ssh://monitor1-ssh#1) 上，运行如下 SQL 命令，查看 `test` 下的表 `tbl_no_ime_R1`，`tbl_ime_R1`，`tbl_no_ime_R2`，`tbl_ime_R2`，`tbl_no_ime_R3` 和 `tbl_ime_R3` 在 TiKV 集群上的分布情况。输出结果中，列 `DB_NAME` 表示 schema 名，列 `TABLE_NAME` 表示表名， 列 `ADDRESS` 表示所在的 TiKV 节点地址，列 `IS_LEADER` 表示是否为 LEASER 角色 Region，`1` 为是， `0` 为否，列 `IS_LEARNER` 表示是否为 LEARNER 角色 Region，`1` 为是， `0` 为否，列 `REGION COUNT` 表示 Region 的数量。

  ```sql
  SELECT
    rs.`DB_NAME`,
    rs.`TABLE_NAME`,
    s.ADDRESS,
    r.`IS_LEADER`,
    r.`IS_LEARNER`,
    COUNT(r.REGION_ID) "REGION COUNT"
  FROM
    INFORMATION_SCHEMA.TIKV_REGION_PEERS r,
    INFORMATION_SCHEMA.TIKV_STORE_STATUS s,
    INFORMATION_SCHEMA.tikv_region_status rs
  WHERE r.STORE_ID = s.STORE_ID
    AND r.`REGION_ID` = rs.`REGION_ID`
    AND rs.`DB_NAME` = 'test'
    AND rs.`TABLE_NAME` IN ('tbl_no_ime_R1', 'tbl_no_ime_R2', 'tbl_no_ime_R3', 'tbl_ime_R1', 'tbl_ime_R2', 'tbl_ime_R3')
    AND r.`IS_LEARNER`=0
  GROUP BY rs.`DB_NAME`,
    rs.`TABLE_NAME`,
    s.`ADDRESS`,
    r.`IS_LEADER`,
    r.`IS_LEARNER`
    ORDER BY r.`IS_LEADER` DESC, rs.`DB_NAME`, s.ADDRESS, rs.`TABLE_NAME`;
  ```

  ```output
  +---------+---------------+-------------------+-----------+------------+--------------+
  | DB_NAME | TABLE_NAME    | ADDRESS           | IS_LEADER | IS_LEARNER | REGION COUNT |
  +---------+---------------+-------------------+-----------+------------+--------------+
  | test    | tbl_ime_R2    | 10.90.3.147:20160 |         1 |          0 |            4 |
  | test    | tbl_no_ime_R2 | 10.90.3.147:20160 |         1 |          0 |            4 |
  | test    | tbl_ime_R1    | 10.90.3.49:20160  |         1 |          0 |            4 |
  | test    | tbl_no_ime_R1 | 10.90.3.49:20160  |         1 |          0 |            4 |
  | test    | tbl_ime_R3    | 10.90.3.51:20160  |         1 |          0 |            4 |
  | test    | tbl_no_ime_R3 | 10.90.3.51:20160  |         1 |          0 |            4 |
  | test    | tbl_ime_R1    | 10.90.3.147:20160 |         0 |          0 |            4 |
  | test    | tbl_ime_R3    | 10.90.3.147:20160 |         0 |          0 |            4 |
  | test    | tbl_no_ime_R1 | 10.90.3.147:20160 |         0 |          0 |            4 |
  | test    | tbl_no_ime_R3 | 10.90.3.147:20160 |         0 |          0 |            4 |
  | test    | tbl_ime_R2    | 10.90.3.49:20160  |         0 |          0 |            4 |
  | test    | tbl_ime_R3    | 10.90.3.49:20160  |         0 |          0 |            4 |
  | test    | tbl_no_ime_R2 | 10.90.3.49:20160  |         0 |          0 |            4 |
  | test    | tbl_no_ime_R3 | 10.90.3.49:20160  |         0 |          0 |            4 |
  | test    | tbl_ime_R1    | 10.90.3.51:20160  |         0 |          0 |            4 |
  | test    | tbl_ime_R2    | 10.90.3.51:20160  |         0 |          0 |            4 |
  | test    | tbl_no_ime_R1 | 10.90.3.51:20160  |         0 |          0 |            4 |
  | test    | tbl_no_ime_R2 | 10.90.3.51:20160  |         0 |          0 |            4 |
  +---------+---------------+-------------------+-----------+------------+--------------+
  18 rows in set (0.02 sec)
  ```

+ 从上一个 SQL 命令的结果可以得到如下结论：
  + 表 `tbl_no_ime_R1` 和 `tbl_ime_R1` 的 PLACEMENT POLICY 为 `IME_R1`，表示它们所有的 LEADER 角色 Region 都存储在 `region1` 的 TiKV 节点上，对其进行的读写默认也在 `region1` 的 TiKV 节点上。
  + 表 `tbl_no_ime_R2` 和 `tbl_ime_R2` 的 PLACEMENT POLICY 为 `IME_R2`，表示它们所有的 LEADER 角色 Region 都存储在 `region2` 的 TiKV 节点上，对其进行的读写默认也在 `region2` 的 TiKV 节点上。
  + 表 `tbl_no_ime_R3` 和 `tbl_ime_R3` 的 PLACEMENT POLICY 为 `IME_R3`，表示它们所有的 LEADER 角色 Region 都存储在 `region3` 的 TiKV 节点上，对其进行的读写默认也在 `region3` 的 TiKV 节点上。

+ `test` 下的表 `tbl_no_ime_R1`，`tbl_ime_R1`，`tbl_no_ime_R2`，`tbl_ime_R2`，`tbl_no_ime_R3` 和 `tbl_ime_R3` 在 TiKV 集群上的分布情况，如下图所示，其中 `tbl_ime_R1`，`tbl_ime_R2` 和 `tbl_ime_R3` 的数据量比 `tbl_no_ime_R1`，`tbl_no_ime_R2` 和 `tbl_no_ime_R3` 多的原因是它们在插入时进行了更新（UPDATE）操作，表中含有了大量的 MVCC 的历史快照数据。

  ![IME_PART2_TABLES_2.png 70%](https://lab-static.pingcap.com/images/2025/8/20/9d9cf59417c092f62c7c584d41ca26a3fa8bc058.png)

+ 在[终端 1](ssh://monitor1-ssh#1) 上，运行下面两个 SQL 命令，分别对表 `test.tbl_no_ime_R1` 和 `test.tbl_ime_R1` 进行查询。

  ```sql
  SELECT sID, ID, txt FROM test.tbl_no_ime_R1 USE INDEX (pcStateIndex) WHERE ((pState = 's1') OR (pState = 's2') OR (pState = 's3')) OR ((pState = 's3' AND cState = 10) OR (pState = 's3' AND cState = 20)) AND NOT (sID = 200001 AND ID = 1097) AND NOT (sID = 0 AND ID = 0) LIMIT 50;
  SELECT sID, ID, txt FROM test.tbl_ime_R1 USE INDEX (pcStateIndex) WHERE ((pState = 's1') OR (pState = 's2') OR (pState = 's3')) OR ((pState = 's3' AND cState = 10) OR (pState = 's3' AND cState = 20)) AND NOT (sID = 200001 AND ID = 1097) AND NOT (sID = 0 AND ID = 0) LIMIT 50;
  EXIT
  ```

  ```output
  +--------+-----+---------+
  | sID    | ID  | txt     |
  +--------+-----+---------+
  | 203063 | 275 | IMETEST |
  | 203099 | 901 | IMETEST |
  ...
  | 295013 | 475 | IMETEST |
  | 297637 | 920 | IMETEST |
  +--------+-----+---------+
  50 rows in set (0.03 sec)

  mysql> SELECT sID, ID, txt FROM test.tbl_ime_R1 USE INDEX (pcStateIndex) WHERE ((pState = 's1') OR (pState = 's2') OR (pState = 's3')) OR ((pState = 's3' AND cState = 10) OR (pState = 's3' AND cState = 20)) AND NOT (sID = 200001 AND ID = 1097) AND NOT (sID = 0 AND ID = 0) LIMIT 50;
  +--------+-----+---------+
  | sID    | ID  | txt     |
  +--------+-----+---------+
  | 203120 | 248 | IMETEST |
  | 205100 | 158 | IMETEST |
  ...
  | 296901 | 455 | IMETEST |
  | 297482 | 113 | IMETEST |
  +--------+-----+---------+
  50 rows in set (0.02 sec)

  mysql> EXIT
  Bye
  ```

+ 转到 [TiDB PD Dashboard](http://${LAB:HOST_PD1_PUBLIC_IP}:2379/dashboard) 并使用用户名 `root` 登录，目前不需要密码。导航到 `SQL Statements` 面板，将显示时间更改为 `Recent 5 min`。

  ![60%](https://lab-static.pingcap.com/quick-demo/ime-off-dashboard-time-1.png)

+ 选择数据库为 `test`。

  ![60%](https://lab-static.pingcap.com/quick-demo/ime-off-dashboard-db-2.png)

+ 将显示的操作设置为 `Select`。

  ![IME_PART2_DASHBOARD_1.png 70%](https://lab-static.pingcap.com/images/2025/8/19/f5b0606c31a88d5ed4ef29a11154046f4f92f7d9.png)

+ 选取以 `SELECT 'sid', 'id' , 'txt' FROM 'test'. 'tbl_no_ime_r1' WHERE ...` 开头的 SQL 命令，该 SQL 命令是对于表 `test.tbl_no_ime_r1` 的查询操作，点击进入。

  ![IME_PART2_DASHBOARD_2.png 70%](https://lab-static.pingcap.com/images/2025/8/19/28355b3509e4076a27cde011953fd7ffdd042e86.png)

+ 查看 `Execution Detail` 中的 `Execution Plan` 项目，找到算子 `Limit_13(Build)`，查看其 `Execution Info` 信息，发现 `total_process_keys` 为 `96`，`total_keys` 为 `97`，说明表中需要扫描过滤的行数和实际存储的总行数类似。

  ![IME_PART2_DASHBOARD_3.png 70%](https://lab-static.pingcap.com/images/2025/8/19/2fd7e5de180aa79f99ce50b3ac69ffd6327aa26a.png)

+ 查看 `Execution Detail` 中的 `Coprocessor Read` 项目，发现 `Mean Visible Versions Per Query` 为 `146`， 发现 `Mean Meet Versions Per Query` 为 `197`，两个项目值相似，因为 `Mean Meet Versions Per Query` 的数值中可能含有 MVCC 历史快照数据，所以说明该查询并没有扫描过多的 MVCC 历史快照数据。

  ![IME_PART2_DASHBOARD_4.png 70%](https://lab-static.pingcap.com/images/2025/8/19/69e9763ec43113a737fbd97458b25b3258f92871.png)

+ 返回上一页，选取以 `SELECT 'sid, 'id' , 'txt' FROM 'test'. 'tbl_ime_r1' WHERE (（...` 开头的 SQL 命令，该 SQL 命令是对于表 `test.tbl_ime_r1` 的查询操作，点击进入。

  ![IME_PART2_DASHBOARD_5.png 70%](https://lab-static.pingcap.com/images/2025/8/19/2d51f054945395ca95606fddc14bb7354523501d.png)

+ 查看 `Execution Detail` 中的 `Execution Plan` 项目，找到步骤 `Limit_13(Build)`，查看其 `Execution Info` 信息，发现 `total_process_keys` 为 `96`，`total_keys` 为 `1865`，说明表中需要扫描过滤的行数比实际存储的总行数少很多。（输出结果可能会略有不同）

  ![IME_PART2_DASHBOARD_6.png 70%](https://lab-static.pingcap.com/images/2025/8/19/94b738494b9f66c89fd9d13462c604820a0f082b.png)

+ 查看 `Execution Detail` 中的 `Coprocessor Read` 项目，发现 `Mean Visible Versions Per Query` 为 `146`， 发现 `Mean Meet Versions Per Query` 为 `2.3K`，两个项目值相差很大，因为 `Mean Meet Versions Per Query` 的数值中可能含有 MVCC 历史快照数据，所以说明该查询会扫描过多的 MVCC 历史快照数据。（输出结果可能会略有不同）

  ![IME_PART2_DASHBOARD_7.png 70%](https://lab-static.pingcap.com/images/2025/8/19/6103fc9a975764597ec03bb44d2a3e54e83a7d35.png)

+ 注意：类似对于表 `test.tbl_ime_r1` 的查询操作，如果执行计划中发现某个算子的 `Execution Info` 信息中 `total_process_keys` 与 `total_keys` 相差较大，则该查询操作适合使用 TiKV MVCC 内存引擎特性进行优化。对于表 `tbl_no_ime_R2` 与 `tbl_ime_R2` 的查询和表 `tbl_no_ime_R3` 与 `tbl_ime_R3` 的查询也会有类似结果，这里省略。

### 步骤 5. TiKV MVCC 内存引擎的使用

+ 了解 TiKV MVCC 内存引擎的使用情况，登录 [Grafana 监控](http://${LAB:HOST_MONITOR1_PUBLIC_IP}:3000)，进入`Home`，然后选择`tidb-demo`，接着选择`tidb-demo-TiKV-Details`， 打开 `In Memory Engine` 标签， 在 `In Memory Engine` 标签下可以看到 `Region Cache Hit`，`Region Cache Hit Rate` 和 `Region Cache Miss Reason` 面板。（`Region Cache Hit` 表示成功从 TiKV MVCC 内存引擎中检索数据的次数，而 `Region Cache Hit Rate` 表示 TiKV MVCC 内存引擎的命中率， `Region Cache Miss Reason` 面板表示某个已经开启 TiKV MVCC 内存引擎的 TiKV 节点没有使用到 TiKV MVCC 内存引擎的查询个数）关于 `tidb-demo-TiKV-Details` 的 `In Memory Engine` 标签中的各个面板，请参考：<https://docs.pingcap.com/zh/tidb/stable/grafana-tikv-dashboard/#in-memory-engine>。

  ![IME_PART2_TiKV_DETAIL_IME_1.png 70%](https://lab-static.pingcap.com/images/2025/8/20/90706bc00ff24f6ca060b5fad2bf527d8b3e165b.png)

+ 在[终端 2](ssh://monitor1-ssh#2) 上，使用 tiup bench 工具对表 `test.tbl_ime_R1` 进行扫描，扫描会持续进行，请不要等待扫描结束并马上执行后面的操作。

  ```bash
  cat > query_tbl_ime_R1.sql <<EOF
  SELECT sID, ID, txt FROM test.tbl_ime_R1 USE INDEX (pcStateIndex) WHERE ((pState = 's1') OR (pState = 's2') OR (pState = 's3')) OR ((pState = 's3' AND cState = 10) OR (pState = 's3' AND cState = 20)) AND NOT (sID = 200001 AND ID = 1097) AND NOT (sID = 0 AND ID = 0) LIMIT 50;
  EOF
  tiup bench rawsql run -H ${HOST_DB1_PRIVATE_IP} -P 4000 --count 300000 --threads 1 --query-files query_tbl_ime_R1.sql
  ```

  ```output
  Starting component bench: /home/ec2-user/.tiup/components/bench/v1.12.0/tiup-bench rawsql run -H 10.90.1.40 -P 4000 --count 300000 --threads 1 --query-files query_tbl_ime_R1.sql
  [Current] QUERY_TBL_IME_R1: 0.00s
  [Current] QUERY_TBL_IME_R1: 0.00s
  ...
  ```

+ 在[终端 3](ssh://monitor1-ssh#3) 上，使用 tiup bench 工具对表 `test.tbl_ime_R2` 进行扫描，扫描会持续进行，请不要等待扫描结束并马上执行后面的操作。

  ```bash
  cat > query_tbl_ime_R2.sql <<EOF
  SELECT sID, ID, txt FROM test.tbl_ime_R2 USE INDEX (pcStateIndex) WHERE ((pState = 's1') OR (pState = 's2') OR (pState = 's3')) OR ((pState = 's3' AND cState = 10) OR (pState = 's3' AND cState = 20)) AND NOT (sID = 200001 AND ID = 1097) AND NOT (sID = 0 AND ID = 0) LIMIT 50;
  EOF
  tiup bench rawsql run -H ${HOST_DB1_PRIVATE_IP} -P 4000 --count 300000 --threads 1 --query-files query_tbl_ime_R2.sql
  ```

  ```output
  Starting component bench: /home/ec2-user/.tiup/components/bench/v1.12.0/tiup-bench rawsql run -H 10.90.1.40 -P 4000 --count 300000 --threads 1 --query-files query_tbl_ime_R2.sql
  [Current] QUERY_TBL_IME_R2: 0.00s
  [Current] QUERY_TBL_IME_R2: 0.00s
  ...
  ```

+ 在[终端 4](ssh://monitor1-ssh#4) 上，使用 tiup bench 工具对表 `test.tbl_ime_R3` 进行扫描，扫描会持续进行，请不要等待扫描结束并马上执行后面的操作。

  ```bash
  cat > query_tbl_ime_R3.sql <<EOF
  SELECT sID, ID, txt FROM test.tbl_ime_R3 USE INDEX (pcStateIndex) WHERE ((pState = 's1') OR (pState = 's2') OR (pState = 's3')) OR ((pState = 's3' AND cState = 10) OR (pState = 's3' AND cState = 20)) AND NOT (sID = 200001 AND ID = 1097) AND NOT (sID = 0 AND ID = 0) LIMIT 50;
  EOF
  tiup bench rawsql run -H ${HOST_DB1_PRIVATE_IP} -P 4000 --count 300000 --threads 1 --query-files query_tbl_ime_R3.sql
  ```

  ```output
  Starting component bench: /home/ec2-user/.tiup/components/bench/v1.12.0/tiup-bench rawsql run -H 10.90.1.40 -P 4000 --count 300000 --threads 1 --query-files query_tbl_ime_R3.sql
  [Current] QUERY_TBL_IME_R3: 0.00s
  [Current] QUERY_TBL_IME_R3: 0.00s
  ...
  ```

+ 回到 [Grafana 监控](http://${LAB:HOST_MONITOR1_PUBLIC_IP}:3000)，在 `tidb-demo-TiKV-Details` 的 `In Memory Engine` 标签，通过 `Region Cache Hit`，`Region Cache Hit Rate` 和 `Region Cache Miss Reason` 面板了解到，目前只有 `region2` 的 TiKV 节点上的查询操作使用了 TiKV MVCC 内存引擎， 其 `Region Cache Hit` 和 `Region Cache Hit Rate` 开始上升，`Region Cache Miss Reason` 没有变化或者开始下降。 `region1` 的 TiKV 节点没有开启 TiKV MVCC 内存引擎，所以没有显示。 `region3` 的 TiKV 节点开启了 TiKV MVCC 内存引擎， 但其 `Region Cache Miss Reason` 开始上升， `Region Cache Hit` 和 `Region Cache Hit Rate` 没有上升，如下图所示：

  ![IME_PART2_TiKV_DETAIL_IME_2.png 70%](https://lab-static.pingcap.com/images/2025/8/20/81c0ace60004a955c1fc8b6151228031d935ab67.png)

+ `region3` 的 TiKV 节点虽然开启了 TiKV MVCC 内存引擎，但并没有使用的原因是其 `in-memory-engine.mvcc-amplification-threshold` 设置为 `100`， 而其实际 MVCC 读放大值并没有达到 `100`，如下图所示：

  ![IME_PART2_TABLES_3.png 70%](https://lab-static.pingcap.com/images/2025/8/20/91006e2a198dd866153d54c31fd36715a3fe6fae.png)

### 步骤 6. TiKV MVCC 内存引擎的设置

+ 在[终端 1](ssh://monitor1-ssh#1) 上，连接到 TiDB 服务器实例。

  ```bash
  mysql -h ${HOST_DB1_PRIVATE_IP} --port 4000 -u root
  ```

  ```output
  mysql> 
  ```

+ 在[终端 1](ssh://monitor1-ssh#1) 上， 查询所有 TiKV 节点关于 TiKV MVCC 内存引擎的配置。

  ```sql
  show config where type='tikv' and name like 'in-memory-engine%';
  ```

  ```output
  +------+-------------------+-----------------------------------------------+------------+
  | Type | Instance          | Name                                          | Value      |
  +------+-------------------+-----------------------------------------------+------------+
  | tikv | 10.90.3.49:20160  | in-memory-engine.capacity                     | 1GiB       |
  | tikv | 10.90.3.49:20160  | in-memory-engine.cross-check-interval         | 0s         |
  | tikv | 10.90.3.49:20160  | in-memory-engine.enable                       | false      |
  | tikv | 10.90.3.49:20160  | in-memory-engine.evict-threshold              | null       |
  | tikv | 10.90.3.49:20160  | in-memory-engine.gc-run-interval              | 3m         |
  | tikv | 10.90.3.49:20160  | in-memory-engine.load-evict-interval          | 2m         |
  | tikv | 10.90.3.49:20160  | in-memory-engine.mvcc-amplification-threshold | 5          |
  | tikv | 10.90.3.49:20160  | in-memory-engine.stop-load-threshold          | null       |
  | tikv | 10.90.3.147:20160 | in-memory-engine.capacity                     | 1GiB       |
  | tikv | 10.90.3.147:20160 | in-memory-engine.cross-check-interval         | 0s         |
  | tikv | 10.90.3.147:20160 | in-memory-engine.enable                       | true       |
  | tikv | 10.90.3.147:20160 | in-memory-engine.evict-threshold              | 966367642B |
  | tikv | 10.90.3.147:20160 | in-memory-engine.gc-run-interval              | 3m         |
  | tikv | 10.90.3.147:20160 | in-memory-engine.load-evict-interval          | 2m         |
  | tikv | 10.90.3.147:20160 | in-memory-engine.mvcc-amplification-threshold | 5          |
  | tikv | 10.90.3.147:20160 | in-memory-engine.stop-load-threshold          | 805306369B |
  | tikv | 10.90.3.51:20160  | in-memory-engine.capacity                     | 1GiB       |
  | tikv | 10.90.3.51:20160  | in-memory-engine.cross-check-interval         | 0s         |
  | tikv | 10.90.3.51:20160  | in-memory-engine.enable                       | true       |
  | tikv | 10.90.3.51:20160  | in-memory-engine.evict-threshold              | 966367642B |
  | tikv | 10.90.3.51:20160  | in-memory-engine.gc-run-interval              | 3m         |
  | tikv | 10.90.3.51:20160  | in-memory-engine.load-evict-interval          | 2m         |
  | tikv | 10.90.3.51:20160  | in-memory-engine.mvcc-amplification-threshold | 100        |
  | tikv | 10.90.3.51:20160  | in-memory-engine.stop-load-threshold          | 805306369B |
  +------+-------------------+-----------------------------------------------+------------+
  24 rows in set (0.04 sec)
  ```

+ 在[终端 1](ssh://monitor1-ssh#1) 上， 修改 `region3` 的 TiKV 节点的 `in-memory-engine.mvcc-amplification-threshold` 为 `5`， 这里请根据你当前的 TiKV 节点 IP 地址进行配置。

  ```sql
  set config "10.90.3.51:20160" `in-memory-engine.mvcc-amplification-threshold`=5;
  show config where instance='10.90.3.51:20160' and type='tikv' and name like 'in-memory-engine%';
  ```

  ```output
  mysql> set config "10.90.3.51:20160" `in-memory-engine.mvcc-amplification-threshold`=5;
  Query OK, 0 rows affected (0.02 sec)

  mysql> show config where instance='10.90.3.51:20160' and type='tikv' and name like 'in-memory-engine%';
  +------+------------------+-----------------------------------------------+------------+
  | Type | Instance         | Name                                          | Value      |
  +------+------------------+-----------------------------------------------+------------+
  | tikv | 10.90.3.51:20160 | in-memory-engine.capacity                     | 1GiB       |
  | tikv | 10.90.3.51:20160 | in-memory-engine.cross-check-interval         | 0s         |
  | tikv | 10.90.3.51:20160 | in-memory-engine.enable                       | true       |
  | tikv | 10.90.3.51:20160 | in-memory-engine.evict-threshold              | 966367642B |
  | tikv | 10.90.3.51:20160 | in-memory-engine.gc-run-interval              | 3m         |
  | tikv | 10.90.3.51:20160 | in-memory-engine.load-evict-interval          | 2m         |
  | tikv | 10.90.3.51:20160 | in-memory-engine.mvcc-amplification-threshold | 5          |
  | tikv | 10.90.3.51:20160 | in-memory-engine.stop-load-threshold          | 805306369B |
  +------+------------------+-----------------------------------------------+------------+
  8 rows in set (0.04 sec)
  ```

+ 回到 [Grafana 监控](http://${LAB:HOST_MONITOR1_PUBLIC_IP}:3000)，在 `tidb-demo-TiKV-Details` 的 `In Memory Engine` 标签，大概在上一个操作的 2 分钟后，可以发现 `region2` 的 TiKV 节点上的查询操作使用了 TiKV MVCC 内存引擎， 其 `Region Cache Hit` 和 `Region Cache Hit Rate` 开始上升，`Region Cache Miss Reason` 开始下降。 `region1` 的 TiKV 节点没有开启 TiKV MVCC 内存引擎，所以依然没有显示。如下图所示：

  ![IME_PART2_TiKV_DETAIL_IME_3.png 70%](https://lab-static.pingcap.com/images/2025/8/20/bd29215aa8cd1d0ef3ec57080ea5df96c1c00f77.png)

+ 在[终端 1](ssh://monitor1-ssh#1) 上，修改 `region1` 的 TiKV 节点的 `in-memory-engine.enable` 为 `true`，这里请根据你当前的 TiKV 节点 IP 地址进行配置.

  ```sql
  set config "10.90.3.49:20160" `in-memory-engine.in-memory-engine.enable`=true;
  show config where instance='10.90.3.49:20160' and type='tikv' and name like 'in-memory-engine%';
  ```

  ```output
  mysql> set config "10.90.3.49:20160" `in-memory-engine.in-memory-engine.enable`=true;
  Query OK, 0 rows affected, 1 warning (0.02 sec)

  mysql> show config where instance='10.90.3.49:20160' and type='tikv' and name like 'in-memory-engine%';
  +------+------------------+-----------------------------------------------+-------+
  | Type | Instance         | Name                                          | Value |
  +------+------------------+-----------------------------------------------+-------+
  | tikv | 10.90.3.49:20160 | in-memory-engine.capacity                     | 1GiB  |
  | tikv | 10.90.3.49:20160 | in-memory-engine.cross-check-interval         | 0s    |
  | tikv | 10.90.3.49:20160 | in-memory-engine.enable                       | false |
  | tikv | 10.90.3.49:20160 | in-memory-engine.evict-threshold              | null  |
  | tikv | 10.90.3.49:20160 | in-memory-engine.gc-run-interval              | 3m    |
  | tikv | 10.90.3.49:20160 | in-memory-engine.load-evict-interval          | 2m    |
  | tikv | 10.90.3.49:20160 | in-memory-engine.mvcc-amplification-threshold | 5     |
  | tikv | 10.90.3.49:20160 | in-memory-engine.stop-load-threshold          | null  |
  +------+------------------+-----------------------------------------------+-------+
  8 rows in set (0.04 sec)
  ```

+ 在[终端 1](ssh://monitor1-ssh#1) 上，断开客户端连接。

  ```sql
  EXIT
  ```

  ```output
  mysql> EXIT
  Bye
  ```

+ `region1` 的 TiKV 节点的 `in-memory-engine.enable` 依然为 `false`，原因是目前无法在线修改 TiKV 节点的 TiKV MVCC 内存引擎特性. 回到 [Grafana 监控](http://${LAB:HOST_MONITOR1_PUBLIC_IP}:3000)，在 `tidb-demo-TiKV-Details` 的 `In Memory Engine` 标签，可以发现 `region2` 和 `region3` 的 TiKV 节点上的查询均使用了 TiKV 节点的 TiKV MVCC 内存引擎特性，`region1` 的 TiKV 节点没有使用 TiKV MVCC 内存引擎特性。注意：你的结果可能和实验指导的结果有差异， `Region Cache Hit Rate`面板中 `region2` 和 `region3` 的 TiKV 节点上的查询可能不会都达到 100%。

  ![IME_PART2_TiKV_DETAIL_IME_4.png 70%](https://lab-static.pingcap.com/images/2025/8/20/e5257af6fe90759a655b933107efe62755f595d4.png)

+ `region1`，`region2` 和 `region3` 的 TiKV 节点的 TiKV MVCC 内存引擎使用情况如下图所示：

  ![IME_PART2_TABLES_4.png 70%](https://lab-static.pingcap.com/images/2025/8/20/53cdfb65f295287f19db24284b4147b8327a5630.png)

+ 在[终端 2](ssh://monitor1-ssh#2) 上，按**CTRL-C**停止 tiup bench 工具对表 `test.tbl_ime_R1` 进行扫描。

  ```output
  ...
  [Current] QUERY_TBL_IME_R1: 0.00s
  [Current] QUERY_TBL_IME_R1: 0.00s
  ^C
  Got signal [interrupt] to exit.
  Got signal interrupt (Component: bench ; PID: 23009)
  Finished
  [Summary] QUERY_TBL_IME_R1: 0.00s
  [Summary] QUERY_TBL_IME_R1_ERR: 0.00s
  ...
  ```

+ 在[终端 3](ssh://monitor1-ssh#3) 上，按**CTRL-C**停止 tiup bench 工具对表 `test.tbl_ime_R2` 进行扫描。

  ```output
  [Current] QUERY_TBL_IME_R2: 0.00s
  [Current] QUERY_TBL_IME_R2: 0.00s
  ^C
  Got signal [interrupt] to exit.
  Got signal interrupt (Component: bench ; PID: 23314)
  Finished
  [Summary] QUERY_TBL_IME_R2: 0.00s
  [Summary] QUERY_TBL_IME_R2_ERR: 0.00s
  ```

+ 在[终端 4](ssh://monitor1-ssh#4) 上，按**CTRL-C**停止 tiup bench 工具对表 `test.tbl_ime_R3` 进行扫描。

  ```output
  [Current] QUERY_TBL_IME_R3: 0.00s
  [Current] QUERY_TBL_IME_R3: 0.00s
  ^C
  Got signal [interrupt] to exit.
  Got signal interrupt (Component: bench ; PID: 23495)
  [ec2-user@ip-10-90-4-217 ~]$ Finished
  [Summary] QUERY_TBL_IME_R3: 0.00s
  ```

+ 在[终端 2](ssh://monitor1-ssh#2) 上，使用 tiup bench 工具对表 `test.tbl_no_ime_R1` 进行扫描，扫描会持续进行，请不要等待扫描结束，并马上执行后面的操作。

  ```bash
  cat > query_tbl_no_ime_R1.sql <<EOF
  SELECT sID, ID, txt FROM test.tbl_no_ime_R1 USE INDEX (pcStateIndex) WHERE ((pState = 's1') OR (pState = 's2') OR (pState = 's3')) OR ((pState = 's3' AND cState = 10) OR (pState = 's3' AND cState = 20)) AND NOT (sID = 200001 AND ID = 1097) AND NOT (sID = 0 AND ID = 0) LIMIT 50;
  EOF
  tiup bench rawsql run -H ${HOST_DB1_PRIVATE_IP} -P 4000 --count 300000 --threads 1 --query-files query_tbl_no_ime_R1.sql
  ```

  ```output
  Starting component bench: /home/ec2-user/.tiup/components/bench/v1.12.0/tiup-bench rawsql run -H 10.90.1.40 -P 4000 --count 300000 --threads 1 --query-files query_tbl_no_ime_R1.sql
  [Current] QUERY_TBL_NO_IME_R1: 0.00s
  [Current] QUERY_TBL_NO_IME_R1: 0.00s
  ...
  ```

+ 在[终端 3](ssh://monitor1-ssh#3) 上，使用 tiup bench 工具对表 `test.tbl_no_ime_R2` 进行扫描，扫描会持续进行，请不要等待扫描结束，并马上执行后面的操作。

  ```bash
  cat > query_tbl_no_ime_R2.sql <<EOF
  SELECT sID, ID, txt FROM test.tbl_no_ime_R2 USE INDEX (pcStateIndex) WHERE ((pState = 's1') OR (pState = 's2') OR (pState = 's3')) OR ((pState = 's3' AND cState = 10) OR (pState = 's3' AND cState = 20)) AND NOT (sID = 200001 AND ID = 1097) AND NOT (sID = 0 AND ID = 0) LIMIT 50;
  EOF
  tiup bench rawsql run -H ${HOST_DB1_PRIVATE_IP} -P 4000 --count 300000 --threads 1 --query-files query_tbl_no_ime_R2.sql
  ```

  ```output
  Starting component bench: /home/ec2-user/.tiup/components/bench/v1.12.0/tiup-bench rawsql run -H 10.90.1.40 -P 4000 --count 300000 --threads 1 --query-files query_tbl_no_ime_R2.sql
  [Current] QUERY_TBL_NO_IME_R2: 0.00s
  [Current] QUERY_TBL_NO_IME_R2: 0.00s
  ...
  ```

+ 在[终端 4](ssh://monitor1-ssh#4) 上，使用 tiup bench 工具对表 `test.tbl_no_ime_R3` 进行扫描，扫描会持续进行，请不要等待扫描结束，并马上执行后面的操作。

  ```bash
  cat > query_tbl_no_ime_R3.sql <<EOF
  SELECT sID, ID, txt FROM test.tbl_no_ime_R3 USE INDEX (pcStateIndex) WHERE ((pState = 's1') OR (pState = 's2') OR (pState = 's3')) OR ((pState = 's3' AND cState = 10) OR (pState = 's3' AND cState = 20)) AND NOT (sID = 200001 AND ID = 1097) AND NOT (sID = 0 AND ID = 0) LIMIT 50;
  EOF
  tiup bench rawsql run -H ${HOST_DB1_PRIVATE_IP} -P 4000 --count 300000 --threads 1 --query-files query_tbl_no_ime_R3.sql
  ```

  ```output
  Starting component bench: /home/ec2-user/.tiup/components/bench/v1.12.0/tiup-bench rawsql run -H 10.90.1.40 -P 4000 --count 300000 --threads 1 --query-files query_tbl_no_ime_R3.sql
  [Current] QUERY_TBL_NO_IME_R3: 0.00s
  [Current] QUERY_TBL_NO_IME_R3: 0.00s
  ...
  ```

+ 回到 [Grafana 监控](http://${LAB:HOST_MONITOR1_PUBLIC_IP}:3000)，在 `tidb-demo-TiKV-Details` 的 `In Memory Engine` 标签，通过 `Region Cache Hit`，`Region Cache Hit Rate` 和 `Region Cache Miss Reason` 面板了解到，目前除 `region1` 的 TiKV 节点没有开启 TiKV MVCC 内存引擎，所以没有显示外，`region2` 和 `region3` 的 TiKV 节点上的查询操作均没有使用 TiKV MVCC 内存引擎， 其 `Region Cache Hit` 和 `Region Cache Hit Rate` 没有上升并保持较低值，`Region Cache Miss Reason` 开始上升并保持较高值。 原因是表 `test.tbl_no_ime_R2` 和 `test.tbl_no_ime_R3` 的 MVCC 读放大值没有超过 `region2` 和 `region3` 的 TiKV 节点中 `in-memory-engine.mvcc-amplification-threshold` 的设定值 `5`，如下图所示：

  ![IME_PART2_TiKV_DETAIL_IME_5.png 70%](https://lab-static.pingcap.com/images/2025/8/20/b1059224ed5b1a0294322bd29b75cac387251649.png)

+ 在[终端 2](ssh://monitor1-ssh#2) 上，按**CTRL-C**停止 tiup bench 工具对表 `test.tbl_no_ime_R1` 进行扫描。

  ```output
  ...
  [Current] QUERY_TBL_NO_IME_R1: 0.00s
  [Current] QUERY_TBL_NO_IME_R1: 0.00s
  ^C
  Got signal [interrupt] to exit.
  Got signal interrupt (Component: bench ; PID: 23800)
  Finished
  [Summary] QUERY_TBL_NO_IME_R1: 0.00s
  [Summary] QUERY_TBL_NO_IME_R1_ERR: 0.00s
  ...
  ```

+ 在[终端 3](ssh://monitor1-ssh#3) 上，按**CTRL-C**停止 tiup bench 工具对表 `test.tbl_no_ime_R2` 进行扫描。

  ```output
  [Current] QUERY_TBL_NO_IME_R2: 0.00s
  [Current] QUERY_TBL_NO_IME_R2: 0.00s
  ^C
  Got signal [interrupt] to exit.
  Got signal interrupt (Component: bench ; PID: 23768)
  Finished
  [Summary] QUERY_TBL_NO_IME_R2: 0.00s
  [Summary] QUERY_TBL_NO_IME_R2_ERR: 0.00s
  ```

+ 在[终端 4](ssh://monitor1-ssh#4) 上，按**CTRL-C**停止 tiup bench 工具对表 `test.tbl_no_ime_R3` 进行扫描。

  ```output
  [Current] QUERY_TBL_NO_IME_R3: 0.00s
  [Current] QUERY_TBL_NO_IME_R3: 0.00s
  ^C
  Got signal [interrupt] to exit.
  Got signal interrupt (Component: bench ; PID: 23809)
  [ec2-user@ip-10-90-4-217 ~]$ Finished
  [Summary] QUERY_TBL_NO_IME_R3: 0.00s
  ```

### 步骤 7. 清理数据

+ 在[终端 1](ssh://monitor1-ssh#1) 上，连接到 TiDB 服务器实例。

  ```bash
  mysql -h ${HOST_DB1_PRIVATE_IP} --port 4000 -u root
  ```

  ```output
  mysql> 
  ```

+ 在[终端 1](ssh://monitor1-ssh#1) 上， 清理本模块使用的所有数据。

  ```sql
  DROP TABLE IF EXISTS test.tbl_no_ime_R1;
  DROP TABLE IF EXISTS test.tbl_no_ime_R2;
  DROP TABLE IF EXISTS test.tbl_no_ime_R3;

  DROP TABLE IF EXISTS test.tbl_ime_R1;
  DROP TABLE IF EXISTS test.tbl_ime_R2;
  DROP TABLE IF EXISTS test.tbl_ime_R3;

  DROP SEQUENCE IF EXISTS test.seq_ime_R1;
  DROP SEQUENCE IF EXISTS test.seq_ime_R2;
  DROP SEQUENCE IF EXISTS test.seq_ime_R3;

  EXIT
  ```

  ```output
  mysql> DROP TABLE IF EXISTS test.tbl_no_ime_R1;
  Query OK, 0 rows affected (0.17 sec)

  mysql> DROP TABLE IF EXISTS test.tbl_no_ime_R2;
  Query OK, 0 rows affected (0.14 sec)

  mysql> DROP TABLE IF EXISTS test.tbl_no_ime_R3;
  Query OK, 0 rows affected (0.14 sec)

  mysql> 
  mysql> DROP TABLE IF EXISTS test.tbl_ime_R1;
  Query OK, 0 rows affected (0.14 sec)

  mysql> DROP TABLE IF EXISTS test.tbl_ime_R2;
  Query OK, 0 rows affected (0.13 sec)

  mysql> DROP TABLE IF EXISTS test.tbl_ime_R3;
  Query OK, 0 rows affected (0.13 sec)

  mysql> 
  mysql> DROP SEQUENCE IF EXISTS test.seq_ime_R1;
  Query OK, 0 rows affected (0.12 sec)

  mysql> DROP SEQUENCE IF EXISTS test.seq_ime_R2;
  Query OK, 0 rows affected (0.13 sec)

  mysql> DROP SEQUENCE IF EXISTS test.seq_ime_R3;
  Query OK, 0 rows affected (0.13 sec)

  mysql>   EXIT;
  Bye
  ```

+ 本模块到此结束。
