CONCAT字符串到longblog和mysql磁盘使用情况

时间:2019-01-01 22:06:11

标签: mysql innodb

如果我是一个innodb表,那么此查询将执行很多操作(一段时间内每秒一次,并附加少量数据)并且具有innodb_files_per_table = 0会导致存储问题吗? Blob本身可能是2-3MB,但我丢失了30gb的数据使用量,并且想知道这段代码是否应归咎于我,或者我是否应该在其他地方查找。

SQL

UPDATE phppos_app_files 
SET file_data = CONCAT(file_data, "NEW LINE OF DATA")
WHERE file_id = 10;

模式:

mysql> show create table phppos_app_files;
+------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table            | Create Table                                                                                                                                                                                                                                                                                                                                                                                                             |
+------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| phppos_app_files | CREATE TABLE `phppos_app_files` (
  `file_id` int(10) NOT NULL AUTO_INCREMENT,
  `file_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `file_data` longblob NOT NULL,
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `expires` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`file_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7577 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
+------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> 

博客列中存储的数据为2-3 mb的日志文本;只是纯文本。我要问的问题是,如果您从当前值开始连接的频繁更新查询是否导致存储问题,从而导致数据库出现严重问题。我只想确保它只存储最少的信息,并且concat更新是否会导致任何大的磁盘问题。

3 个答案:

答案 0 :(得分:1)

在存储和访问BLOB时,频繁更新小数据块可能会由于碎片而浪费大量空间。有可能要考虑的优化方法:

  • explained in this documentation的形式在存储之前进行压缩(可能与您的用例有关,因为BLOB会存储文本)
  • 定期运行OPTIMIZE TABLE command,以重新组织物理存储。如Bill Karwin所言,禁用选项innodb_file_per_table不会缩小表空间。但是,它将回收由于碎片而丢失的空间,并将其标记为表空间内的可用空间:因此,它将在重新增长表空间之前重新利用任何空范围。

答案 1 :(得分:1)

如果您频繁更新大型Blob,则确实确实可能会临时使用大量存储,并使表空间碎片化。

更新将原始数据页复制到“撤消日志”,该撤消日志只是表空间中的页面区域。如果您回滚事务并必须还原原始数据,InnoDB会保留这些复制的页面。提交更新后,不再需要撤消日志中的副本,并且InnoDB将逐渐清理。但是,如果您说的更新很频繁,则在InnoDB中清除垃圾的速度可能比InnoDB清除垃圾的速度快。

无论如何,为更多的撤消日志内容扩展存储空间将扩大表空间,即使在InnoDB清理后,表空间也不会缩小。它将始终保持其高水位线的大小。

为减轻这种情况,MySQL 5.6引入了一个选项,允许将撤消日志存储在系统表空间之外,而MySQL 5.7引入了一项功能,用于在清除撤消日志后将其截断。阅读https://dev.mysql.com/doc/refman/5.7/en/innodb-undo-tablespaces.html,以获取有关这些功能的更多信息。


如果您对InnoDB文件的内部布局感兴趣,建议您尝试使用开源工具Jeremy Cole写道:https://github.com/jeremycole/innodb_ruby/wiki

您可以转储ibdata1表空间中各种内容的摘要。许多文件可能尚未使用,但仍占用空间。

这是我本地MySQL沙箱中的一个示例。我只有一个带有innondb_file_per_table=0的表(其他所有表都在中央表空间之外)。我运行了以下命令:

innodb_space -s /usr/local/var/mysql/ibdata1 -T mydatabase/mytable space-extents-illustrate

这是它创建的插图。图例(不包括在内)表明,我的一个表的数据和索引位于3008到3392之间的页面中。其他内容主要是InnoDB系统数据结构(黑色),系统表,插入缓冲区(深黄色)和空置的页(灰色)。

enter image description here

答案 2 :(得分:0)

您可以使用下面的查询来检查表的大小。这样,您可以看到哪个表浪费了您的存储空间。

SELECT 
     table_schema as `Database`, 
     table_name AS `Table`, 
     round(((data_length + index_length) / 1024 / 1024), 2) `Size in MB` 
FROM information_schema.TABLES 
ORDER BY (data_length + index_length) DESC

实际上,已使用的总空间保持不变。

如果使用innodb_files_per_table=0,则只有一个表空间,并且由于数据变化很快,因此表空间可能会随时间碎片化。

如果您将来决定删除或截断表,则表空间大小将保持不变(不会缩小),因此无法从删除操作中重新获得空间。