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)

EDIT2:NOT NULLすべての列に設定することで、さらに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 |
+---------------+--------------+---------+

あなたのテーブルにはどれくらいのストレージが必要ですか? Data Type Storage Requirementsを確認しましょう:

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

ここで、L は文字バイト数で、通常は 1 文字あたり 1 バイトですが、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 の間) は、test2 つの列が 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% の数字も推定であるため、残りは翻訳で失われると確信しています.

別の理由として、 で Unicode 文字セットを使用しているsources場合testが考えられます。この場合、一部の文字はそれぞれ複数のバイトを使用する可能性がありますが、NULL 可能な列がすべてを説明しているように見えるため、これはあなたのテーブルには当てはまらないと思います。

概要

  • 2 つのテーブルのサイズは同じではなく、30 MB 異なります。
  • 新しいテーブルのサイズは、予想されるサイズとほぼ同じです。
  • protid1protid2NOT NULL列にすることで、新しいテーブルのスペースをさらに節約できます。
于 2015-12-22T10:03:18.247 に答える
0

「テーブル」は.MYDファイルに保存されます。このファイルは、またはによって縮小されることはありません。 (または同等の へのクエリ) は縮小を示す場合がありますが、増加します。UPDATEsDELETEsSHOW TABLE STATUSinformation_schemaData_lengthData_free

を実行すると、.MYDファイルを圧縮できますOPTIMIZE TABLE。ただし、それはテーブルをコピーするため、プロセス中に追加のディスク領域が必要になります。そして、このアクションが実行に値することはめったにありません。

NOT NULLnull が多数ある場合、に変更してもスペースが解放されない場合があります。"" はVARCHAR、長さのために、a に 1 または 2 バイトかかります。(そして、あなたのコードは '' を '' とは異なる方法で処理する必要があるかもしれませんNULL。)

各行に必要なスペースは、実際には前述よりも 1 バイト多くなります。このバイトは、行が存在するか、それとも穴の始まりであるかを認識します。

大きなテキスト フィールドの場合、スペースを節約するためにこれを行うのが好きです。BLOB(これは MyISAM と InnoDB の両方に適用されます。) テキストを圧縮し、 ( の代わりに) 列に格納しますTEXT。ほとんどのテキストでは、これは 3:1 の収縮です。クライアントで少し余分なコードと CPU 時間を必要としますが、サーバーでの I/O を大幅に節約できます。多くの場合、最終的な結果は「高速」です。あなたが持っている varchar には使用しません。たとえば、平均50文字よりも大きな列でのみ実行します。

元の質問に戻ります。テーブル全体で約 30M のコロンとセミコロンしかなかったようです。最初の 10 行は代表的ではないのでしょうか?

于 2015-12-22T20:51:28.447 に答える