【问题标题】:How to calculate the diskspace used by MySQL table from column datatypes and number of rows?如何从列数据类型和行数计算 MySQL 表使用的磁盘空间?
【发布时间】:2018-05-28 06:47:53
【问题描述】:

我有一个 MySQL 表,在 Google Cloud SQL 上托管了超过 30 亿行。

我想了解如何从列数据类型、行数和索引来解释磁盘上的总大小。

我希望它会是这样的

size_of_table_in_bytes = num_rows * [ Sum over i {bytes_for_datatype_of_column(i))}
                                    + Sum over j  {Bytes_for_index(j)} ]

但我最终得到的磁盘大小不正确,而不是我的数据库大小显示的大小。

在上使用每个数据类型的字节数

https://dev.mysql.com/doc/refman/5.7/en/storage-requirements.html

以及来自

的 InnoDB 标头和索引中的其他字节

https://dev.mysql.com/doc/refman/5.7/en/innodb-physical-record.html#innodb-compact-row-format-characteristics

这里是我对header、每列和每一个索引占用的字节数的理解

TABLE `depth` (
Bytes| Column/Header/Index
    2| variable length header Ceil(num columns/8) = Ceil (10/8)
    5| Fixed Length Header
    3|`date` date DEFAULT NULL,
    7|`receive_time` datetime(3) DEFAULT NULL,
    8|`instrument_token` bigint(20) unsigned DEFAULT NULL,
    1|`level `tinyint(3) unsigned DEFAULT NULL,
    2|`bid_count` smallint(5) unsigned DEFAULT NULL,
    8|`bid_size` bigint(20) unsigned DEFAULT NULL,
    4|`bid_price` float DEFAULT NULL,
    4|`ask_price` float DEFAULT NULL,
    8|`ask_size` bigint(20) unsigned DEFAULT NULL,
    2|`ask_count` smallint(5) unsigned DEFAULT NULL,
    6|KEY `date_time_sym (`date`,`receive_time`,`instrument_token`),
    6|KEY `date_sym_time (`date`,`instrument_token`,`receive_time`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8`

总计 72 个字节。

但根据 SHOW TABLE STATUS,Avg_row_length = 79。

问题 1:我在哪里弄错了每行的字节数?

我有理由确定我的数据中没有空值。

假设,我在计算字节数时犯了一些错误,每行使用 79 个字节 并使用SELECT COUNT(*) 作为3,017,513,240 计算行数:

size_of_table_in_bytes = 79*3,017,513,240 = 238,383,545,960

另一种获取大小的方法是使用 MySQL 查询

SHOW TABLE STATUS from mktdata where Name = "depth";

这里我得到一个包含一行的表格输出,其中几个重要字段的值如下:

Name: depth
Engine:InnoDB
Version:10
Row_format:Dynamic
Rows: 1,72,08,21,447 
Avg_row_length: 78
Index_length: 1,83,90,03,07,456
Data_length:  1,35,24,53,32,480 

起初我很震惊,Rows 是 17 亿而不是 30.1 亿,但我在documentation 中发现了这个

  • 行

行数。一些存储引擎,例如 MyISAM,存储确切的 数数。对于其他存储引擎,例如 InnoDB,这个值是一个近似值,可能与实际值相差 40% 到 50%。在这种情况下,请使用 SELECT COUNT(*) 获得准确的计数。

因此,30.1 亿似乎适合行数,因此我预计表大小为 238 GB。

但是,如果我把 Data_length 和 Index_length 加起来,我得到 319,145,639,936

问题 2:为什么我用一种方法得到 319 GB 而另一种方法得到 238 GB。如果有的话,哪一个是正确的?

此外,Google Cloud SQL 控制台显示的 SQL 数据库的总大小为 742 GB。我唯一拥有的另一张表trade 的行数正好是depth 的1/5 和5 列。将Data_length 和Index_length 相加的大小为57 GB。如果我添加两个表大小,我会得到 376 GB。

问题 3:742 GB 似乎大约是 376 GB(实际上是 752)的两倍。这可能是因为备份?我知道 Google Cloud SQL 每天会自动备份一次?

由于上述问题3的合理性,我怀疑我的size = num_rows*num_bytes_per_row的简单方法是错误的!这真的让我很困扰,并会感谢任何帮助解决这个问题。

【问题讨论】:

  • 您使用的是MySQL而不是MS SQL Server,请删除SQL-Server标签
  • 您是否启用了二进制日志?如果是,您还必须考虑它们的大小。
  • 谢谢,我刚刚检查了 log_bin = ON。如何检查它的大小?
  • SHOW BINARY LOGS;
  • 我得到一个以 Log_name,File_size 作为列的表。 872 行的 File_size 总和为 85,661,147,002。这解释了 85 GB 的磁盘空间?

标签: mysql database google-cloud-platform google-cloud-sql


【解决方案1】:
  • 开销比您提到的要多。 20 字节/行可能关闭。
  • 不要相信 SHOW TABLE STATUS 提供“行”,使用 SELECT COUNT(*) ... 注意它是如何减少了近 2 倍。
  • 用另一种方式计算:135245332480 / 3017513240 = 45 字节。
  • 从 45 个字节,我推断很多单元格是 NULL?
  • 每一行中的每一列都有 1 或 2 字节的开销。
  • ROW_FORMAT 很重要。
  • TEXT 和 BLOB(等)的规则与简单数据类型完全不同。
  • 索引占用的字节数远远超过您提到的 6 个字节(请参阅您的 other posting)。
  • BTree 结构有一些开销。按顺序加载时,每个块的 15/16 被填充(在文档中的某处提到)。流失后,范围很容易被填充 50-100%; BTree 被吸引到 69% 的满(因此其他帖子中的 1.45)。

为备份保留等量的空间...

  • 我不知道他们是否正在这样做。
  • 如果他们使用 mysqldump(或类似的),这不是一个安全的公式 - 数据库的 text 转储可能显着更大或更小。
  • 如果他们使用 LVM,那么他们就有空间进行完整的二进制转储。但这没有意义,因为 COW。
  • (所以,我放弃了 Q3。)

云服务可以进行某种压缩吗?

【讨论】:

  • 磁盘使用不包括备份(它们单独存储)。正如我在之前的评论中提到的,其余的磁盘使用可能来自二进制日志。
  • ROW_FORMAT=动态。没有 TEXT 或 BLOB 列。是的索引我后来意识到的事情。不可能有这么多空值。我会数数。
  • Vadim,Google Cloud 提供了一个可视化界面,在我的数据库中显示 750+ GB。我需要问他们是否包括备份。感谢您的日志评论,解释了 85 GB。
  • 我在谷歌云上工作。正如我在第一条评论中提到的,显示的磁盘使用情况不包含与备份相关的任何内容。
猜你喜欢
  • 1970-01-01
  • 2011-03-13
  • 2011-02-19
  • 1970-01-01
  • 2010-11-19
  • 2023-03-17
  • 1970-01-01
  • 2011-11-10
  • 1970-01-01
相关资源
最近更新 更多