## 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 进行过滤的复制** 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. 源写入其二进制日志。“假人”[**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; ```