为什么 InnoDB 给出明显错误的 free space 信息
Why does InnoDB give obviously false free space information
我想知道在删除相当大的 table 后我的数据库有多少范围("free space")。 (大约 10GB)
我有运行命令:
SELECT table_schema "Data Base Name",
round( sum( data_free ) / 1024 / 1024 / 1024 ) "Free Space in GB"
FROM information_schema.TABLES
GROUP BY table_schema;
它给了我一个数据库列表,以及它们的 "free spaces"。
问题是,根据这份报告,删除了 10GB table 的数据库现在有 1500GB 以上的可用空间 space,这 比我的实际硬盘驱动器大得多容量。 (大约 200GB)
这怎么可能?我怎样才能得到更真实的报告?我错过了什么吗?
更新
作为实验,我在此数据库中添加和删除了 1GB table,现在报告显示大约 110GB 的可用空间 space。可能是我的配置有问题,还是这是一个常见问题?
听起来好像您没有设置 innondb_file_per_table,因此正在使用共享的 table space。如果是这样,那么您将为每个 table_schema.
重复生成全局 'allocated but unused' 共享 space
(这是在回答埋藏在评论中的一些问题。)
用词不当 "Free" space 只包括整块,不包括块内的空闲空间,以及许多其他细节。
情况 1:所有 table 都在 ibdata1
-- SHOW TABLE STATUS
(或 information_schema
中的等效查询将显示相同的 Data_free
值,即 ibdata1
中有多少可用。这个 space 可以被任何 table 重复使用。很难给出 space回到OS.
情况 2:所有 table 都是 file_per_table
-- 现在每个 Data_free
都指代 space table。 SUM()
是有意义的。 (ibdata1 仍然存在,但它不包含任何真实的 tables;InnoDB 需要很多其他东西。)
Case 3: Mixture -- 如果你在不同的时间转file_per_table on/off,一些tables会在ibdata1中,有些人会有自己的 tablespaces.
案例 4:在 5.7 中创建表空间 -- 例如,您可以为每个数据库创建一个 tablespace。
案例 5:PARTITIONed tables -- 每个分区都像 table.
案例 6:8.0 -- 更多变化即将到来。
Database == Directory 在MySQL的目录树中,每个数据库都可以看作是一个文件系统目录。在该目录中可以看到每个 table 的一些文件集。 .frm
文件包含 table 定义。如果 .ibd
文件存在,则 table 是用 file_per_table 创建的。这可能是发现 table 是否为 file_per_table 的最可靠方法。 (8.0 将在此处进行重大更改。)
我可以重复使用多少space?没有好的答案。通常插入一行会在所属的块中找到space,而Data_free不会收缩。但是,如果有块拆分,Data_free 可能会下降 16KB(块大小)或 4MB("extent size" - 或者可能是 8MB?)的某个倍数。此外,随机插入导致 BTree 块平均占满 69%。
更改 innodb_file_per_table
在下一个 CREATE TABLE
或 ALTER TABLE
之前没有任何效果。然后它只影响新 created/copied 数据+索引(ibdata1 或 .ibd)的放置位置。它不会破坏数据。
大tables通常有4MB到7MB的Data_free。在计算可以添加的行数时,不要计划 Data_free 低于该范围。
Avg_row_size应该有用。但有时它(和行)的近似值很差。他们的产品 (Data_length) 总是正确的。因此,这 可能 是对“在从 OS:
中获取更多 space 之前要走的行数的一个很好的估计
(Data_free - 7M) / Avg_row_size
Tablespace 建议:将'big' tables 放入file_per_table。将 'tiny' tables 放入 ibdata1 或数据库特定的 tablespaces (5.7)。抱歉,'big'和'tiny'之间的分界线没有简单的推荐。而且迁移一个table很笨拙:SET global innodb_file_per_table = ...;
;登出;登录(获取全局); ALTER TABLE tbl ENGINE=InnoDB;
。而且它必然是 table.
的完整副本
(警告:我遗漏了很多细节。)
我想知道在删除相当大的 table 后我的数据库有多少范围("free space")。 (大约 10GB)
我有运行命令:
SELECT table_schema "Data Base Name",
round( sum( data_free ) / 1024 / 1024 / 1024 ) "Free Space in GB"
FROM information_schema.TABLES
GROUP BY table_schema;
它给了我一个数据库列表,以及它们的 "free spaces"。
问题是,根据这份报告,删除了 10GB table 的数据库现在有 1500GB 以上的可用空间 space,这 比我的实际硬盘驱动器大得多容量。 (大约 200GB)
这怎么可能?我怎样才能得到更真实的报告?我错过了什么吗?
更新
作为实验,我在此数据库中添加和删除了 1GB table,现在报告显示大约 110GB 的可用空间 space。可能是我的配置有问题,还是这是一个常见问题?
听起来好像您没有设置 innondb_file_per_table,因此正在使用共享的 table space。如果是这样,那么您将为每个 table_schema.
重复生成全局 'allocated but unused' 共享 space(这是在回答埋藏在评论中的一些问题。)
用词不当 "Free" space 只包括整块,不包括块内的空闲空间,以及许多其他细节。
情况 1:所有 table 都在 ibdata1
-- SHOW TABLE STATUS
(或 information_schema
中的等效查询将显示相同的 Data_free
值,即 ibdata1
中有多少可用。这个 space 可以被任何 table 重复使用。很难给出 space回到OS.
情况 2:所有 table 都是 file_per_table
-- 现在每个 Data_free
都指代 space table。 SUM()
是有意义的。 (ibdata1 仍然存在,但它不包含任何真实的 tables;InnoDB 需要很多其他东西。)
Case 3: Mixture -- 如果你在不同的时间转file_per_table on/off,一些tables会在ibdata1中,有些人会有自己的 tablespaces.
案例 4:在 5.7 中创建表空间 -- 例如,您可以为每个数据库创建一个 tablespace。
案例 5:PARTITIONed tables -- 每个分区都像 table.
案例 6:8.0 -- 更多变化即将到来。
Database == Directory 在MySQL的目录树中,每个数据库都可以看作是一个文件系统目录。在该目录中可以看到每个 table 的一些文件集。 .frm
文件包含 table 定义。如果 .ibd
文件存在,则 table 是用 file_per_table 创建的。这可能是发现 table 是否为 file_per_table 的最可靠方法。 (8.0 将在此处进行重大更改。)
我可以重复使用多少space?没有好的答案。通常插入一行会在所属的块中找到space,而Data_free不会收缩。但是,如果有块拆分,Data_free 可能会下降 16KB(块大小)或 4MB("extent size" - 或者可能是 8MB?)的某个倍数。此外,随机插入导致 BTree 块平均占满 69%。
更改 innodb_file_per_table
在下一个 CREATE TABLE
或 ALTER TABLE
之前没有任何效果。然后它只影响新 created/copied 数据+索引(ibdata1 或 .ibd)的放置位置。它不会破坏数据。
大tables通常有4MB到7MB的Data_free。在计算可以添加的行数时,不要计划 Data_free 低于该范围。
Avg_row_size应该有用。但有时它(和行)的近似值很差。他们的产品 (Data_length) 总是正确的。因此,这 可能 是对“在从 OS:
中获取更多 space 之前要走的行数的一个很好的估计(Data_free - 7M) / Avg_row_size
Tablespace 建议:将'big' tables 放入file_per_table。将 'tiny' tables 放入 ibdata1 或数据库特定的 tablespaces (5.7)。抱歉,'big'和'tiny'之间的分界线没有简单的推荐。而且迁移一个table很笨拙:SET global innodb_file_per_table = ...;
;登出;登录(获取全局); ALTER TABLE tbl ENGINE=InnoDB;
。而且它必然是 table.
(警告:我遗漏了很多细节。)