复制 MySQL/MariaDB BLOB 列时复制了哪些数据?
What data is duplicated when MySQL/MariaDB BLOB columns are copied?
让table_1
创建如下:
CREATE TABLE table_1 (
id INT AUTO_INCREMENT PRIMARY KEY,
some_blob BLOB
);
让table_2
创建如下:
CREATE TABLE table_2 (
id INT AUTO_INCREMENT PRIMARY KEY,
some_blob BLOB
);
我想知道的是,在我运行这个table复制查询
之后
INSERT INTO table_2 (id, some_blob) SELECT id, some_blob FROM table_1;
table_1
table 的每个 some_blob
字段中的实际文本是否会被复制并存储在磁盘上,或者数据库是否只有指向包含BLOB 数据?
为什么 BLOB 复制必须涉及复制实际内容的一个论据如下:
Duplication of BLOB content is necessary because changes to BLOB data in table_1
should not also take place in table_2
. If only the disk pointers were duplicated then content changes in one table would be reflected in the other table, which violates the properties of a correct copy operation.
现在我提出数据库可以实现的另一种方法来满足此复制操作。这个备选方案表明上述论点不一定正确。 DB 只能在给定的 INSERT
语句执行期间复制磁盘指针,然后每当 UPDATE
发生试图修改其中一个 table 中的 BLOB 数据时,DB 将然后才在磁盘上分配更多 space 来存储作为 UPDATE
查询一部分的新数据。 BLOB 数据段只有在不再存在任何指向它的磁盘指针时才会被删除,并且特定的 BLOB 数据段可能有许多指向它的磁盘指针。
那么 MySQL/MariaDB 在执行给定的 INSERT
语句时使用了哪些策略,还是使用了不同的策略?
编辑:为什么我要问这个问题
目前我运行正在执行几个 UPDATE
查询,这些查询正在将大量 BLOB 数据从一个 table 复制到同一数据库中的另一个(超过 1000 万行BLOB 数据)。查询已经 运行ning 一段时间了。我很好奇性能这么慢是不是因为我比较的一些列的索引很差,因为这些查询实际上是在复制内容而不是磁盘指针,或者可能是因为这两个原因。
我在问题示例中使用了 INSERT
,因为这简化了我试图理解的数据库内部概念。
每个 table 都有自己的 blob 数据和所有其他数据的副本。 MySQL 不进行数据的浅拷贝。确实,blob 是单独分配的对象,但它们不在 table 之间共享。提供了存储引擎内部结构的描述,以便您了解正在发生的事情,而不是让您可以更改它(除非您分叉存储引擎源并创建一个新版本……但首先让您的应用程序运行)。
因此,您的 UPDATE 查询正在擦除旧的 blob 数据并写入新的。这是 I/O 密集的,所以它可能很慢。
使用 INSERT 作为简化问题的方法是不正确的。将新的 blob 写入 table 比覆盖现有的更快。
您在生产中的最佳选择是避免对 blob 列进行更新。
让table_1
创建如下:
CREATE TABLE table_1 (
id INT AUTO_INCREMENT PRIMARY KEY,
some_blob BLOB
);
让table_2
创建如下:
CREATE TABLE table_2 (
id INT AUTO_INCREMENT PRIMARY KEY,
some_blob BLOB
);
我想知道的是,在我运行这个table复制查询
之后INSERT INTO table_2 (id, some_blob) SELECT id, some_blob FROM table_1;
table_1
table 的每个 some_blob
字段中的实际文本是否会被复制并存储在磁盘上,或者数据库是否只有指向包含BLOB 数据?
为什么 BLOB 复制必须涉及复制实际内容的一个论据如下:
Duplication of BLOB content is necessary because changes to BLOB data in
table_1
should not also take place intable_2
. If only the disk pointers were duplicated then content changes in one table would be reflected in the other table, which violates the properties of a correct copy operation.
现在我提出数据库可以实现的另一种方法来满足此复制操作。这个备选方案表明上述论点不一定正确。 DB 只能在给定的 INSERT
语句执行期间复制磁盘指针,然后每当 UPDATE
发生试图修改其中一个 table 中的 BLOB 数据时,DB 将然后才在磁盘上分配更多 space 来存储作为 UPDATE
查询一部分的新数据。 BLOB 数据段只有在不再存在任何指向它的磁盘指针时才会被删除,并且特定的 BLOB 数据段可能有许多指向它的磁盘指针。
那么 MySQL/MariaDB 在执行给定的 INSERT
语句时使用了哪些策略,还是使用了不同的策略?
编辑:为什么我要问这个问题
目前我运行正在执行几个 UPDATE
查询,这些查询正在将大量 BLOB 数据从一个 table 复制到同一数据库中的另一个(超过 1000 万行BLOB 数据)。查询已经 运行ning 一段时间了。我很好奇性能这么慢是不是因为我比较的一些列的索引很差,因为这些查询实际上是在复制内容而不是磁盘指针,或者可能是因为这两个原因。
我在问题示例中使用了 INSERT
,因为这简化了我试图理解的数据库内部概念。
每个 table 都有自己的 blob 数据和所有其他数据的副本。 MySQL 不进行数据的浅拷贝。确实,blob 是单独分配的对象,但它们不在 table 之间共享。提供了存储引擎内部结构的描述,以便您了解正在发生的事情,而不是让您可以更改它(除非您分叉存储引擎源并创建一个新版本……但首先让您的应用程序运行)。
因此,您的 UPDATE 查询正在擦除旧的 blob 数据并写入新的。这是 I/O 密集的,所以它可能很慢。
使用 INSERT 作为简化问题的方法是不正确的。将新的 blob 写入 table 比覆盖现有的更快。
您在生产中的最佳选择是避免对 blob 列进行更新。