## 16.6 黑洞存储引擎

[](<>)[](<>)

这`黑洞`存储引擎充当“黑洞”，接受数据但将其丢弃而不存储。检索总是返回空结果：

```
mysql> CREATE TABLE test(i INT, c CHAR(10)) ENGINE = BLACKHOLE;
Query OK, 0 rows affected (0.03 sec)

mysql> INSERT INTO test VALUES(1,'record one'),(2,'record two');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM test;
Empty set (0.00 sec)
```

要启用`黑洞`存储引擎，如果你从源代码构建 MySQL，调用**制作**与[`-DWITH_BLACKHOLE_STORAGE_ENGINE`](source-configuration-options.html#option_cmake_storage_engine_options)选项。

检查源`黑洞`发动机，看看`sql`MySQL 源代码分发的目录。

当你创建一个`黑洞`表，服务器在全局数据字典中创建表定义。没有与该表关联的文件。

这`黑洞`存储引擎支持各种索引。也就是说，您可以在表定义中包含索引声明。

从 MySQL 8.0.27 开始，最大密钥长度为 3072 字节。在 8.0.27 之前，最大密钥长度为 1000 字节。

这`黑洞`存储引擎不支持分区。

您可以检查是否`黑洞`存储引擎可与[`显示引擎`](show-engines.html)陈述。

插入一个`黑洞`table 不存储任何数据，但如果启用了基于语句的二进制日志记录，则会记录 SQL 语句并将其复制到副本服务器。这可用作中继器或过滤器机制。

假设您的应用程序需要副本端过滤规则，但首先将所有二进制日志数据传输到副本会导致流量过多。在这种情况下，可以在复制源服务器上设置一个“虚拟”副本进程，其默认存储引擎为`黑洞`，描绘如下：

[](<>)

**图 16.1 使用 BLACKHOLE 进行过滤的复制**

<img alt="The replication source server uses a source mysqld process and a dummy mysqld process. On the replica, the mysqld process replicates from the dummy mysqld process." src="images/blackhole-1.png" height="300" width="575" />

源写入其二进制日志。“假人”[**mysqld**](mysqld.html)过程充当复制品，应用所需的组合`复制做-*`和`复制忽略-*`规则，并写入自己的新过滤二进制日志。（看[第 17.1.6 节，“复制和二进制日志记录选项和变量”](replication-options.html).) 此过滤后的日志提供给副本。

虚拟进程实际上并不存储任何数据，因此运行附加进程所产生的处理开销很小[**mysqld**](mysqld.html)复制源服务器上的进程。可以使用其他副本重复这种类型的设置。

[`插入`](insert.html)触发`黑洞`表按预期工作。然而，由于`黑洞`表实际上并不存储任何数据，[`更新`](update.html)和[`删除`](delete.html)触发器未激活：`每一行`触发器定义中的子句不适用，因为没有行。

其他可能的用途`黑洞`存储引擎包括：

-   验证转储文件语法。

-   通过比较性能来测量二进制日志记录的开销`黑洞`启用和不启用二进制日志记录。

-   `黑洞`本质上是一个“无操作”的存储引擎，因此它可以用于查找与存储引擎本身无关的性能瓶颈。

    这`黑洞`引擎是事务感知的，从某种意义上说，已提交的事务被写入二进制日志，而回滚事务则没有。

**黑洞引擎和自动增量列**

这`黑洞`引擎是无操作引擎。使用对表执行的任何操作`黑洞`没有效果。在考虑自动递增的主键列的行为时，应牢记这一点。引擎不会自动递增字段值，也不会保留自动递增字段状态。这对复制具有重要意义。

考虑以下所有三个条件都适用的复制场景：

1.  在源服务器上，有一个黑洞表，其中包含一个作为主键的自动增量字段。

2.  在副本上存在同一个表，但使用的是 MyISAM 引擎。

3.  插入是在源表中执行的，而无需在`插入`声明本身或通过使用`设置 INSERT_ID`陈述。

    在这种情况下，复制失败，主键列出现重复条目​​错误。

    在基于语句的复制中，值`INSERT_ID`在上下文中事件总是相同的。因此，由于尝试为主键列插入具有重复值的行，复制失败。

    在基于行的复制中，引擎为行返回的值对于每个插入始终是相同的。这导致副本尝试使用相同的主键列值重播两个插入日志条目，因此复制失败。

**列过滤**

使用基于行的复制时，([`binlog_format=行`](replication-options-binary-log.html#sysvar_binlog_format))，支持表中缺少最后一列的副本，如 部分所述[第 17.5.1.9 节，“在源和副本上具有不同表定义的复制”](replication-features-differing-tables.html).

此过滤在副本端起作用，即列在被过滤掉之前被复制到副本中。至少有两种情况不希望将列复制到副本：

1.  如果数据是机密的，那么副本服务器应该无权访问它。

2.  如果源有许多副本，则在发送到副本之前进行过滤可能会减少网络流量。

    源列过滤可以使用`黑洞`引擎。这以类似于实现源表过滤的方式执行 - 通过使用`黑洞`发动机和[`--replicate-do-table`](replication-options-replica.html#option_mysqld_replicate-do-table)要么[`--复制忽略表`](replication-options-replica.html#option_mysqld_replicate-ignore-table)选项。

    源的设置是：


```
CREATE TABLE t1 (public_col_1, ..., public_col_N,
                 secret_col_1, ..., secret_col_M) ENGINE=MyISAM;
```

受信任副本的设置是：

```
CREATE TABLE t1 (public_col_1, ..., public_col_N) ENGINE=BLACKHOLE;
```

不受信任副本的设置是：

```
CREATE TABLE t1 (public_col_1, ..., public_col_N) ENGINE=MyISAM;
```
