5

我需要减小 MySQL 数据库的大小。我重新编码了一些带有';'的信息 和 ':' 来自sources列(约 10% 的字符减少)。这样做之后,桌子的大小和以前完全一样。这怎么可能?我正在使用 MyISAM 引擎。

顺便说一句:不幸的是,我无法使用myisampack.

mysql> INSERT INTO test SELECT protid1, protid2, CS, REPLACE(REPLACE(sources, ':', ''), ';', '') FROM homologs_9606; 
Query OK, 41917131 rows affected (4 min 11.30 sec)
Records: 41917131  Duplicates: 0  Warnings: 0

mysql> select TABLE_NAME name, ROUND(TABLE_ROWS/1e6, 3) 'million rows', ROUND(DATA_LENGTH/power(2,30), 3) 'data GB', ROUND(INDEX_LENGTH/power(2,30), 3) 'index GB' from information_schema.TABLES WHERE TABLE_NAME IN ('homologs_9606', 'test') ORDER BY TABLE_ROWS DESC LIMIT 10;
+---------------+--------------+---------+----------+
| name          | million rows | data GB | index GB |
+---------------+--------------+---------+----------+
| test          |       41.917 |   0.857 |    1.075 |
| homologs_9606 |       41.917 |   0.887 |    1.075 |
+---------------+--------------+---------+----------+
2 rows in set (0.01 sec)

mysql> select * from homologs_9606 limit 10;
+---------+---------+-------+--------------------------------+
| protid1 | protid2 | CS    | sources                        |
+---------+---------+-------+--------------------------------+
| 5635338 | 1028608 | 0.000 | 10:,1                          |
| 5644385 | 1028611 | 0.947 | 5:1,1;8:0.943,35;10:1,1;11:1,1 |
| 5652325 | 1028611 | 0.947 | 5:1,1;8:0.943,35;10:1,1;11:1,1 |
| 5641128 | 1028612 | 1.000 | 8:1,10                         |
| 5636414 | 1028616 | 0.038 | 8:0.038,104;10:,1              |
| 5636557 | 1028616 | 0.000 | 8:,4                           |
| 5637419 | 1028616 | 0.011 | 5:,1;8:0.011,91;10:,1          |
| 5641196 | 1028616 | 0.080 | 5:1,1;8:0.074,94;10:,1;11:,4   |
| 5642914 | 1028616 | 0.000 | 8:,3                           |
| 5643778 | 1028616 | 0.056 | 8:0.057,70;10:,1               |
+---------+---------+-------+--------------------------------+
10 rows in set (4.55 sec)

mysql> select * from test limit 10;
+---------+---------+-------+-------------------------+
| protid1 | protid2 | CS    | sources                 |
+---------+---------+-------+-------------------------+
| 5635338 | 1028608 | 0.000 | 10,1                    |
| 5644385 | 1028611 | 0.947 | 51,180.943,35101,1111,1 |
| 5652325 | 1028611 | 0.947 | 51,180.943,35101,1111,1 |
| 5641128 | 1028612 | 1.000 | 81,10                   |
| 5636414 | 1028616 | 0.038 | 80.038,10410,1          |
| 5636557 | 1028616 | 0.000 | 8,4                     |
| 5637419 | 1028616 | 0.011 | 5,180.011,9110,1        |
| 5641196 | 1028616 | 0.080 | 51,180.074,9410,111,4   |
| 5642914 | 1028616 | 0.000 | 8,3                     |
| 5643778 | 1028616 | 0.056 | 80.057,7010,1           |
+---------+---------+-------+-------------------------+
10 rows in set (0.00 sec)

mysql> describe test;
+---------+------------------+------+-----+---------+-------+
| Field   | Type             | Null | Key | Default | Extra |
+---------+------------------+------+-----+---------+-------+
| protid1 | int(10) unsigned | YES  | PRI | NULL    |       |
| protid2 | int(10) unsigned | YES  | PRI | NULL    |       |
| CS      | float(4,3)       | YES  |     | NULL    |       |
| sources | varchar(100)     | YES  |     | NULL    |       |
+---------+------------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

mysql> describe homologs_9606;
+---------+------------------+------+-----+---------+-------+
| Field   | Type             | Null | Key | Default | Extra |
+---------+------------------+------+-----+---------+-------+
| protid1 | int(10) unsigned | NO   | PRI | 0       |       |
| protid2 | int(10) unsigned | NO   | PRI | 0       |       |
| CS      | float(4,3)       | YES  |     | NULL    |       |
| sources | varchar(100)     | YES  |     | NULL    |       |
+---------+------------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

EDIT1:增加了平均列长度。

mysql> select AVG(LENGTH(sources)) from test; 
+----------------------+
| AVG(LENGTH(sources)) |
+----------------------+
|               5.2177 |
+----------------------+
1 row in set (10.04 sec)

mysql> select AVG(LENGTH(sources)) from homologs_9606; 
+----------------------+
| AVG(LENGTH(sources)) |
+----------------------+
|               6.8792 |
+----------------------+
1 row in set (9.95 sec)

NOT NULLEDIT2:通过设置所有列,我能够剥离更多 MB 。

mysql> drop table test
Query OK, 0 rows affected (0.42 sec)

mysql> CREATE table test (protid1 INT UNSIGNED NOT NULL DEFAULT '0', protid2 INT UNSIGNED NOT NULL DEFAULT '0', CS FLOAT(4,3) NOT NULL DEFAULT '0', sources VARCHAR(100) NOT NULL DEFAULT '0', PRIMARY KEY (protid1, protid2), KEY `idx_protid2` (protid2)) ENGINE=MyISAM CHARSET=ascii;
Query OK, 0 rows affected (0.06 sec)

mysql> INSERT INTO test SELECT protid1, protid2, CS, REPLACE(REPLACE(sources, ':', ''), ';', '') FROM homologs_9606; 
Query OK, 41917131 rows affected (2 min 7.84 sec)

mysql> select TABLE_NAME name, ROUND(TABLE_ROWS/1e6, 3) 'million rows', ROUND(DATA_LENGTH/power(2,30), 3) 'data GB', ROUND(INDEX_LENGTH/power(2,30), 3) 'index GB' from information_schema.TABLES WHERE TABLE_NAME IN ('homologs_9606', 'test');
Records: 41917131  Duplicates: 0  Warnings: 0

+---------------+--------------+---------+----------+
| name          | million rows | data GB | index GB |
+---------------+--------------+---------+----------+
| homologs_9606 |       41.917 |   0.887 |    1.075 |
| test          |       41.917 |   0.842 |    1.075 |
+---------------+--------------+---------+----------+
2 rows in set (0.02 sec)
4

2 回答 2

2

它们并不完全相同。您的查询清楚地表明它test比 30 MB 小homologs_9606

+---------------+--------------+---------+
| name          | million rows | data GB |
+---------------+--------------+---------+
| test          |       41.917 |   0.857 | <-- 0.857 < 0.887
| homologs_9606 |       41.917 |   0.887 |
+---------------+--------------+---------+

我们应该为您的桌子提供多少存储空间?让我们检查数据类型存储要求

INTEGER(10): 4 bytes
FLOAT(4): 4 bytes
VARCHAR(100): L+1

其中 L 是字符字节数,通常每个字符一个字节,但如果使用 Unicode 字符集,有时会更多。

您的行平均需要:

INTEGER + INTEGER + FLOAT + VARCHAR =
4 + 4 + 4 + (L + 1) = L + 13 bytes

我们可以将您的原始平均 L 推断为(0.887*1024^3 / 41917131) - 13 = 9.72。你说你从 中剥离了 10% sources,这意味着你的新 L 是9.72*0.9 = 8.75。这给出了预期的新总存储需求((8.75 + 13) * 41917131) / 1024^3 = 0.849 GB

我怀疑差异(在 0.849 和 0.857 之间)可能是由于test有两列设置为 NULLable 而homologs_9606没有,但我对 MyISAM 引擎的了解不够,无法准确计算。不过我能猜到!至少,每行每列需要 1 位来存储NULL状态,在您的情况下,这意味着每行 2 位或2*41917131 = 83834262 bits = 10 479 283 bytes = 0.010 GB. 总0.849+0.010 = 0.859射门略高于目标(大约 2 MB 太多)。但是我做了一些四舍五入,你的 10% 的数字也是一个估计值,所以我确信其余的在翻译中丢失了。

另一个原因可能是如果您在 in 上使用 Unicode 字符集sourcestest在这种情况下,某些字符可能每个使用多个字节,但是由于 NULLable 列似乎可以解释所有问题,我认为您的表并非如此。

概括

  • 您的两个表大小不同,它们相差 30 MB。
  • 新表的大小大约是预期大小。
  • protid1您可以通过将和protid2放入NOT NULL列来在新表中节省更多空间。
于 2015-12-22T10:03:18.247 回答
0

“表”存储在.MYD文件中。该文件永远不会UPDATEs因为或而缩小DELETEsSHOW TABLE STATUS(或对 的等效查询information_schema)可能会显示Data_length缩小,但Data_free会增加。

您可以通过执行来缩小.MYD文件OPTIMIZE TABLE。但这会将表复制过来,从而在此过程中需要额外的磁盘空间。而这个动作很少值得去做。

NOT NULL如果您有很多空值,更改为可能不会释放空间——“”VARCHAR由于长度的原因需要 1 或 2 个字节。(并且您的代码可能需要以不同于 '' 的方式处理NULL。)

每行占用的空间实际上比前面提到的多 1 个字节——这个字节处理知道该行是否存在或者是一个洞的开始。

对于大文本字段,我喜欢这样做以节省空间。(这适用于 MyISAM 和 InnoDB。)压缩文本并将其存储到BLOB列中(而不是TEXT)。对于大多数文本,这是 3:1 的收缩。它在客户端需要一些额外的代码和 CPU 时间,但在服务器中节省了大量的 I/O。通常,最终结果是“更快”。我不会将它用于您拥有的 varchar;我只会在大于平均 50 个字符的列上执行此操作。

回到最初的问题。听起来整个表中只有大约 30M 的冒号和分号。莫非前10行没有代表性?

于 2015-12-22T20:51:28.447 回答