如何在MySQL中估算/预测表的数据大小和索引大小


26

我正在研究很多博客和论坛,但找不到任何准确答案,因此我发现估算表大小的最佳方法什么?

例如,我们有一个带有InnoDB引擎表City,可以说在未来(未来1年)它将有100万条记录,因此在此期间该表的估计数据大小和索引大小是多少。

mysql> desc City;
+-------------+----------+------+-----+---------+----------------+
| Field       | Type     | Null | Key | Default | Extra          |
+-------------+----------+------+-----+---------+----------------+
| ID          | int(11)  | NO   | PRI | NULL    | auto_increment |
| Name        | char(35) | NO   |     |         |                |
| CountryCode | char(3)  | NO   | MUL |         |                |
| District    | char(20) | NO   |     |         |                |
| Population  | int(11)  | NO   |     | 0       |                |
+-------------+----------+------+-----+---------+----------------+
5 rows in set (0.03 sec)

更新

一百万条记录的估计上限(表的最大大小)将是多少,以及如何估算。


这很棒。但是有可能明智地获得索引大小列。意思是如果您有一个表(例如)索引了5列。我们可以获得每个索引的索引大小吗?我会问另一个问题。谢谢
Sushil 2013年

Answers:


51

给定表描述,我看到

  • 每行数据66个字节
  • 主键每行4个字节
  • 国家/地区代码索引每行7个字节
    • 国家的3个字节
    • 4个字节的集群密钥附加到国家/地区代码
  • 总共77个字节的数据和密钥
  • 这不考虑BTREE或表空间碎片的内部管理

对于一百万行,这将是77,000,000字节(73.43 MB)

至于测量表,对于给定的表mydb.mytable,可以运行此查询

SELECT 
    CONCAT(FORMAT(DAT/POWER(1024,pw1),2),' ',SUBSTR(units,pw1*2+1,2)) DATSIZE,
    CONCAT(FORMAT(NDX/POWER(1024,pw2),2),' ',SUBSTR(units,pw2*2+1,2)) NDXSIZE,
    CONCAT(FORMAT(TBL/POWER(1024,pw3),2),' ',SUBSTR(units,pw3*2+1,2)) TBLSIZE
FROM
(
    SELECT DAT,NDX,TBL,IF(px>4,4,px) pw1,IF(py>4,4,py) pw2,IF(pz>4,4,pz) pw3
    FROM 
    (
        SELECT data_length DAT,index_length NDX,data_length+index_length TBL,
        FLOOR(LOG(IF(data_length=0,1,data_length))/LOG(1024)) px,
        FLOOR(LOG(IF(index_length=0,1,index_length))/LOG(1024)) py,
        FLOOR(LOG(data_length+index_length)/LOG(1024)) pz
        FROM information_schema.tables
        WHERE table_schema='mydb'
        AND table_name='mytable'
    ) AA
) A,(SELECT 'B KBMBGBTB' units) B;

测量按数据库和存储引擎分组的所有表

SELECT
    IF(ISNULL(DB)+ISNULL(ENGINE)=2,'Database Total',
    CONCAT(DB,' ',IFNULL(ENGINE,'Total'))) "Reported Statistic",
    LPAD(CONCAT(FORMAT(DAT/POWER(1024,pw1),2),' ',
    SUBSTR(units,pw1*2+1,2)),17,' ') "Data Size",
    LPAD(CONCAT(FORMAT(NDX/POWER(1024,pw2),2),' ',
    SUBSTR(units,pw2*2+1,2)),17,' ') "Index Size",
    LPAD(CONCAT(FORMAT(TBL/POWER(1024,pw3),2),' ',
    SUBSTR(units,pw3*2+1,2)),17,' ') "Total Size"
FROM
(
    SELECT DB,ENGINE,DAT,NDX,TBL,
    IF(px>4,4,px) pw1,IF(py>4,4,py) pw2,IF(pz>4,4,pz) pw3
    FROM 
    (SELECT *,
        FLOOR(LOG(IF(DAT=0,1,DAT))/LOG(1024)) px,
        FLOOR(LOG(IF(NDX=0,1,NDX))/LOG(1024)) py,
        FLOOR(LOG(IF(TBL=0,1,TBL))/LOG(1024)) pz
    FROM
    (SELECT
        DB,ENGINE,
        SUM(data_length) DAT,
        SUM(index_length) NDX,
        SUM(data_length+index_length) TBL
    FROM
    (
       SELECT table_schema DB,ENGINE,data_length,index_length FROM
       information_schema.tables WHERE table_schema NOT IN
       ('information_schema','performance_schema','mysql')
       AND ENGINE IS NOT NULL
    ) AAA GROUP BY DB,ENGINE WITH ROLLUP
) AAA) AA) A,(SELECT ' BKBMBGBTB' units) B;

运行这些查询,您可以跟踪数据库/引擎磁盘使用情况的变化。

试试看 !!!


1
对于查看所有表大小,这是一个非常好的查询。
ghayes 2014年

CHAR如果有的话,长度需要乘以3 CHARSET utf8。可以通过将计算增加一倍或三倍来估算整个开销。
里克·詹姆斯

@RolandoMySQLDBA,您是否知道是否可以计算表的“实际”行大小,并将目标与实际大小(压缩表)进行比较并获得压缩率?
ceinmart

@ceinmart innodb_page_size是固定的(默认为16K或16384),并成为行和分组或拆分的边界。更改innodb_page_size可以改变数据存储的好坏,基于行的填充或稀疏程度(尤其是存在TEXT / BLOB / VARCHAR的情况)。充其量,您应该将.ibd文件的大小与该模式报告的大小进行比较,以估计比率。您可能还需要执行NULL ALTER TABLE(ALTER TABLE ... ENGINE=InnoDB;)以获取准确的比率。努力可能不值得。
RolandoMySQLDBA

@ceinmart请记住,更改innodb_page_size并不是逐表设置。你需要做一个完整的出口数据(见mariadb.com/kb/en/library/how-to-change-innodb_page_size
RolandoMySQLDBA

4

如果您使用的是InnoDB表,则可以从获取数据/单个索引的大小mysql.innodb_index_stats。“ size”统计信息包含以页为单位的答案,因此您必须将其乘以page-size,默认情况下为16K

select database_name, table_name, index_name, stat_value*@@innodb_page_size
from mysql.innodb_index_stats where stat_name='size';

索引PRIMARY是数据本身。


1
假设您在表中有数据;好像OP想要在填充之前进行估算。
瑞克·詹姆斯

0
SELECT  Table_NAME "tablename",
           data_length   "table data_length in Bytes",
           index_length  "table index_length in Bytes",
           data_free  "Free Space in Bytes"
    FROM  information_schema.TABLES  where  Table_schema = 'databasename';

通过执行此查询,您可以获取用于DataIndex的表的大小,您可以对照行数检查该大小并预测100万行


1
我不确定,但这会给出一些准确的结果吗?你有没有测试过?
Abdul Manaf

实际上,我正在定期测试此查询结果以查看wrt大小的增长(%)
Peter Venderberghe 2013年

0

如果您还没有数据,请参考以下提示。以下内容适用于InnoDB。(MyISAM更简单,更小。)

不要CHAR用于变长列。你CHARACTER SET在用什么 Ascii每个字符需要一个字节;utf8mb4需要1到4之间。

4 bytes per INT
35 for CHAR(35), if ascii or latin1; varchar is probably less
3 for the country code; it is fixed length
etc

总计=大约80个字节。

将80乘以2到3之间即可解决各种开销。1M行表最有可能在160MB和240MB之间。

要测量单个索引(例如CountryCode3个字节):

3 bytes data
4 bytes for the PK (implicitly included with any secondary key)
25 bytes basic overhead
32 total
times 1.5 -- overhead for BTree that was randomly inserted into
48MB -- total for 1M rows.

笔记:

  • 仅需要计算(BTree的)叶节点;非叶节点的开销通常为 1%。

  • PRIMARY KEY是“集群”的数据,所以没有必要计算它。

  • 如果没有显式PK,则需要在行大小上添加6个字节,以允许伪造的PK。

  • ROW_FORMAT = COMPRESSED给您约2:1的收缩率。(这不像典型的3:1 zip(等)压缩率。)

  • SHOW TABLE STATUS LIKE "tablename";是计算“实际”尺寸的快速方法。有关Data_length数据和PK,请参见;Index_length用于二级索引以及Data_free其他一些内容。

  • 很少Index_length超过Data_length。但是,发生这种情况并非“错误”。


-1

这很乏味。但是细节在文档中

为了尽可能精确(这几乎是不必要的),您还需要阅读表结构和索引结构。

如果我不满意,我会建立表格,用一百万行测试数据填充表格,并测量尺寸变化。根据您的应用程序,您可能还需要考虑事务日志文件的大小。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.