Mysql INFORMATION_SCHEMA.INNODB_BUFFER_页面和INFORMATION_SCHEMA.TABLES中的不同数据大小

Mysql INFORMATION_SCHEMA.INNODB_BUFFER_页面和INFORMATION_SCHEMA.TABLES中的不同数据大小,mysql,database-performance,amazon-aurora,Mysql,Database Performance,Amazon Aurora,我试图了解表是否正在加载到InnoDB缓冲区。为此,我正在查询信息\u SCHEMA.INNODB\u BUFFER\u PAGE表。 据我所见,这张桌子已经满了。然而,加载到缓冲区中的数据量(MB)与INFORMATION_SCHEMA.TABLES中显示的数据量大不相同 例如: SELECT TABLE_NAME, TABLE_ROWS , CAST(DATA_LENGTH/POWER(1024,2) AS DECIMAL(5, 0)) AS DATA_LENGTH_MB ,

我试图了解表是否正在加载到InnoDB缓冲区。为此,我正在查询信息\u SCHEMA.INNODB\u BUFFER\u PAGE表。 据我所见,这张桌子已经满了。然而,加载到缓冲区中的数据量(MB)与INFORMATION_SCHEMA.TABLES中显示的数据量大不相同

例如:

SELECT TABLE_NAME, TABLE_ROWS
    , CAST(DATA_LENGTH/POWER(1024,2) AS DECIMAL(5, 0)) AS DATA_LENGTH_MB
    , CAST(DATA_FREE/POWER(1024,2) AS DECIMAL(5, 0)) AS DATA_FREE_MB
FROM INFORMATION_SCHEMA.TABLES 
    FROM INFORMATION_SCHEMA.TABLES 
    WHERE TABLE_SCHEMA = '<db_name>' 
        AND TABLE_NAME = '<table_name>';


| TABLE_NAME   | TABLE_ROWS | DATA_LENGTH_MB | DATA_FREE_MB |
|-----------------------------------------------------------|
| <table_name> | 39735968   | 10516          | 548          |
INNODB_BUFFER_PAGE表中的信息模式包含有关缓冲池中页面的信息

注意最后4个单词

这表明
INNODB\u BUFFER\u PAGE
的总和可能小于从
INFORMATION\u SCHEMA.TABLES
获得的总和

(我不知道所有细节,但这里有一些一般性陈述。)

缓冲池可能包含:

  • 表的部分或全部叶节点
  • 表的部分或所有非叶节点
  • 表的每个非主索引的叶节点和非叶节点同上
  • 更多表格同上
  • 文本和BLOB(以及大的VARCHAR)可能会记录在案。这大大增加了占用的磁盘空间。但我认为你的情况不会发生这种情况。但是,请参见下文
  • 缓冲池的25%(可调)保留给“更改缓冲区”;这是一种用于更改辅助索引的写缓存
  • 其他东西
  • 缓冲池的百分之几被保留或因其他原因丢失
块以[大致]最近使用最少的顺序从缓冲池中踢出

我不知道,但我认为如果一个表的大小是缓冲池的一半,那么在缓冲池中保留一个表可能是不可能的

还有一件事需要注意。。。每个表的无数据度量只是表中相当多的“开销”类别之一

  • 预先分配的块(可能反映在无数据中)
  • 未填充的块(可能没有数据或索引块是100%满的)
  • 事务会产生额外的行拷贝——这些行在undo/redo空间或数据块中来来去去去
  • 块分割
  • 等等
  • 经验法则是数据占用的磁盘空间(数据长度)是预测大小的2-3倍。(“Predicted”=将单个数据大小相加,例如每个
    INT
    加上4个字节)
疯狂的想法

行格式是什么

您的3.5GB计算可能是记录空间,所有
varchar
都存储在记录外。数学几乎算出来了

让我们一起探讨两种思考方式

SELECT count(*),
       AVG(LENGTH(col3)) AS avg3,
       AVG(LENGTH(col5)) AS avg5,
       ...   -- the rest of the VARCHARs
    FROM table_name;

(我特别想要
LENGTH()
,而不是
CHAR\u LENGTH()

抱歉耽搁了这么久。我终于设法确认,事实上有一个数据清理正在讨论的表上执行。大约60%的记录被删除。 这应该可以解释mysql.innodb\u index\u stats表中sizen\u leaf\u pages值之间的差异。不确定这是不是正常行为

所以来回答我的问题。要估计表在InnoDB池中的容量,我可能需要查看mysql.InnoDB_index_statssize而不是INFORMATION_SCHEMA.table

SELECT TABLE_NAME, ROUND((stat_value*@@innodb_page_size)/POWER(1024,2)) AS DATA_SIZE_MB 
FROM mysql.innodb_index_stats 
WHERE database_name = 'db_name' AND index_name = 'PRIMARY' AND table_name = 'table_name' 
    AND stat_name = 'n_leaf_pages';

感谢@Rick James帮助我完成此任务

请提供
SHOW CREATE TABLE
。特别是,我想知道是否有
TEXT
BLOB
列。从选择p.TABLE\u名称、p.INDEX\u名称、页面类型、页面状态、四舍五入(SUM(DATA\u SIZE)/POWER(1024,2))作为数据大小\u MB、SUM(NUMBER\u记录)中可以得到什么AS NUMBER_记录来自信息_SCHEMA.INNODB_BUFFER_页面作为p,其中p.TABLE_名称(如“…”)按1,2,3,4的顺序按p.TABLE_名称、p.INDEX_名称分组;创建附在上面的TABKE语句。没有BLOB或文本列您的语句的输出:TABLE|U NAME | INDEX|U NAME | page|U type | page|U state | DATA|U SIZE | MB | NUMBER|记录------------------------------------------------------------------------------------------主索引|文件| page | 1461 | 19111932看起来大约有50%的te表被删除了自上次以来,极光有一些显著的差异;我不知道它们是否相关。num行的变化并不让我担心,但“3.5GB对10.5GB”似乎非常重要(我的答案中没有任何东西可以解释,即使是挥手)。这些varchar的平均大小是多少?一行的最大值不超过2K,即使假设在整个过程中使用3字节utf8字符——总共90GB。我猜一行通常总共是350字节16GB。(这假设大部分是1字节字符,而varchar不是很满。)因此,您的10.5GB很接近,但3.5GB意味着您的varchar非常空,或者3.5非常低。嗯,我原以为完全加载到内存中的表的数字会非常接近。但现在它大约是磁盘上表大小的30%到60%。我的最终目标是估计有多少表可以加载到内存中。但考虑到数字如此之多,目前我看不出有什么办法可以做到这一点different@RimvydasGurskis-我在回答时又挥了挥手。祝你好运请在此处或以某种形式的博客发布您的发现。ROW|u FORMAT=DynamicHere是平均值:count(*)col3 | col5 | col8 | col11 | col18 47074590 | 6.0000 | 22.3948 | 11.0000 |(null)| 7.2727给定当前大小(3.8 GB)平均行长度约为80字节。这是有道理的,因为大约有一半的列AllowNullSnumbers是mysql。innodb_index_统计数据在我看来很奇怪。大小和n_leaf_pages值之间存在很大差异。选择stat_name、stat_value、ROUND((stat_value*@@innodb_page_size)/POWER(1024,2))作为mysql.innodb_index_stats中的数据_size_MB,其中数据库_name='db_name'和索引_name='PRIMARY'
SELECT COUNT(1) FROM <db_name>.<table_name>;
44947428
CREATE TABLE `table_name` (
    `recid` BINARY(32) NOT NULL,
    `col1` INT(11) UNSIGNED NOT NULL,
    `col2` TINYINT(1) UNSIGNED NOT NULL,
    `col3` VARCHAR(250) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
    `col4` TINYINT(1) UNSIGNED NOT NULL,
    `col5` VARCHAR(250) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
    `col6` TINYINT(1) UNSIGNED NOT NULL,
    `col7` TINYINT(1) UNSIGNED NOT NULL,
    `col8` VARCHAR(100) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
    `col9` TINYINT(1) UNSIGNED NOT NULL,
    `col10` TINYINT(1) UNSIGNED NOT NULL,
    `col11` VARCHAR(100) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
    `col12` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
    `col13` TINYINT(1) UNSIGNED NOT NULL DEFAULT '1',
    `col14` INT(11) UNSIGNED NULL DEFAULT NULL,
    `col15` BINARY(32) NULL DEFAULT NULL,
    `col16` CHAR(2) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
    `col17` TINYINT(1) NULL DEFAULT NULL,
    `col18` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
    `col19` TINYINT(1) NULL DEFAULT NULL,
    `col20` TINYINT(1) NULL DEFAULT NULL,
    PRIMARY KEY (`recid`) USING BTREE,
    UNIQUE INDEX `col3` (`col3`) USING BTREE,
    INDEX `col5` (`col5`) USING BTREE,
    INDEX `col8` (`col8`) USING BTREE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
SELECT count(*),
       AVG(LENGTH(col3)) AS avg3,
       AVG(LENGTH(col5)) AS avg5,
       ...   -- the rest of the VARCHARs
    FROM table_name;
SELECT TABLE_NAME, ROUND((stat_value*@@innodb_page_size)/POWER(1024,2)) AS DATA_SIZE_MB 
FROM mysql.innodb_index_stats 
WHERE database_name = 'db_name' AND index_name = 'PRIMARY' AND table_name = 'table_name' 
    AND stat_name = 'n_leaf_pages';