mysql - 复制 MySQL/MariaDB 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
);
我想知道的是,在我运行这个表复制查询之后
INSERT INTO table_2 (id, some_blob) SELECT id, some_blob FROM table_1;
some_blob
表的每个字段中的实际文本是否会table_1
被复制并存储在磁盘上,或者数据库是否只有重复的指向包含 BLOB 数据的磁盘位置的指针?
关于为什么 BLOB 复制必须涉及复制实际内容的一个论据,原因如下:
BLOB 内容的复制是必要的,因为对 BLOB 数据的更改
table_1
也不应该在table_2
. 如果仅复制磁盘指针,则一个表中的内容更改将反映在另一个表中,这违反了正确复制操作的属性。
现在我提出一种数据库可以实现的替代方法来满足这个复制操作。这个替代方案表明上述论点不一定正确。DB 只能在给定INSERT
语句的执行过程中复制磁盘指针,然后每当UPDATE
发生试图修改其中一个表中的 BLOB 数据的情况时,DB 才会在磁盘上分配更多空间来存储作为一部分的新数据的UPDATE
查询。一个 BLOB 数据段只有在不再存在任何指向它的磁盘指针时才会被删除,并且一个特定的 BLOB 数据段可能有许多指向它的磁盘指针。
那么 MySQL/MariaDB 在执行给定INSERT
语句时使用了哪些策略,还是使用了不同的策略?
编辑:为什么我要问这个问题
目前,我正在运行几个UPDATE
查询,它们将大量 BLOB 数据从一个表复制到同一个数据库中的另一个表(超过 1000 万行 BLOB 数据)。查询已经运行了一段时间。我很好奇性能是否如此缓慢,因为我正在比较的某些列的索引很差,因为这些查询实际上是在复制内容而不是磁盘指针,或者可能是因为这两个原因。
我INSERT
在问题的示例中使用了 an ,因为这简化了我试图理解的数据库内部概念。
解决方案
每个表都有自己的 blob 数据和所有其他数据的副本。MySQL 不做数据的浅拷贝。确实,blob 是单独分配的对象,但它们不在表之间共享。提供了存储引擎内部的描述,以便您可以了解发生了什么,而不是您可以更改它(除非您分叉存储引擎源并创建一个新版本......但首先让您的应用程序运行)。
因此,您的 UPDATE 查询正在擦除旧的 blob 数据并写入新数据。那是 I/O 密集型的,所以它可能很慢。
使用 INSERT 作为简化问题的一种方式是不正确的。将新的 blob 写入表是一个比覆盖现有的更快的过程。
您在生产中的最佳选择是避免对 blob 列进行更新。
推荐阅读
- android - EventBus:两个订阅者:没有订阅者注册事件类 org.greenrobot.eventbus.NoSubscriberEvent
- regex - 检查字符串中的值的函数
- sql - SQL - exclude refunded transactions on new line
- powershell - Oracle 管理单元或模块的可用性
- c# - 我可以在 CASE 中使用 ENUM 而不是带有 Enum 的 switch 语句吗?
- python - 用于决定操作的数据框中的时间戳分析
- xslt - XSL 将特定值排序到最后
- list - Scheme/Racket:将一个列表分成两个元素列表的函数,这些元素匹配某个谓词和不匹配它的元素
- java - 如果我在 URL 中传递动态变量,则 Css 不会应用于我的 JSP 页面。
- java - 如何在 spring-boot 中禁用所有 management.health 端点?