web-dev-qa-db-ja.com

blobを格納するために使用されるMySQL 8 INNODBテーブルの量を測定する方法は?

テーブルのディスク上のファイルサイズと、テーブルに格納されている情報のサイズの不一致を理解しようとしています。

私はRDS(InnoDB、テーブルごとに1つのファイル)でホストされているMySQL 8を使用しているため、ディスクに直接アクセスすることは残念ながら不可能です。

特に1つの表は問題をよく示しています。

mysql> describe prod_insti.workItemContentVersion;
+-----------------------------+--------------+------+-----+---------+-------+
| Field                       | Type         | Null | Key | Default | Extra |
+-----------------------------+--------------+------+-----+---------+-------+
| parentId                    | int(11)      | NO   | PRI | NULL    |       |
| serialNumber                | int(11)      | NO   | PRI | NULL    |       |
| previousVersionSerialNumber | int(11)      | YES  |     | NULL    |       |
| authorPrincipalName         | varchar(256) | YES  |     | NULL    |       |
| textAnswer                  | longtext     | YES  |     | NULL    |       |
| textAnswerContentType       | varchar(10)  | YES  |     | NULL    |       |
| blobAnswer                  | longblob     | YES  |     | NULL    |       |
| contentSavedOn              | datetime     | YES  |     | NULL    |       |
+-----------------------------+--------------+------+-----+---------+-------+

この答え は、InnoDBテーブルのサイズを取得する正しい方法が次のようであることを示しています。

mysql> SELECT
    ->     table_name AS `Table`,
    ->     round(((data_length + index_length) / 1024 / 1024), 2) `Size in MB`
    -> FROM information_schema.TABLES
    -> WHERE table_schema = 'prod_insti'
    -> AND table_name = 'workItemContentVersion';
+------------------------+------------+
| Table                  | Size in MB |
+------------------------+------------+
| workItemContentVersion | 1398809.50 |
+------------------------+------------+

ただし、RDSを介して報告される実際のディスク使用量は、これよりもはるかに高くなります。 information_schemaテーブルを調べたところ、最終的に次の情報が見つかりました。これは、観測されたディスク使用量とより密接に一致しています。

mysql> select name, row_format, round(file_size / 1024 / 1024) as 'File size in MB', round(allocated_size / 1024 / 1024) as 'Allocated size in MB' from information_schema.INNODB_TABLESPACES where name = 'prod_insti/workItemContentVersion';
+-----------------------------------+------------+-----------------+----------------------+
| name                              | row_format | File size in MB | Allocated size in MB |
+-----------------------------------+------------+-----------------+----------------------+
| prod_insti/workItemContentVersion | Compressed |         2779672 |              2779677 |
+-----------------------------------+------------+-----------------+----------------------+

参照ドキュメントはこちら を精査すると、DATA_LENGTH属性は実際にはInnoDBテーブルのクラスター化インデックスの最も近いページに丸められた長さのようです。

今、さらに( ブログ記事公式ドキュメント )InnoDBテーブルのROW_FORMATがDYNAMICまたはCOMPRESSEDの場合、BLOBおよびLONGTEXT列はほとんどクラスタ化インデックスに格納されず、独自の「オーバーフロー」セクション(または何か?.

したがって、私の仮説は、DATA_LENGTHが単にこのテーブルのBLOBまたはTEXTカラムによって使用されているスペースを報告しないというものです。

私の質問:

これが理にかなっていることの確認を探しています。もしそうなら、このテーブルのBLOB/TEXTカラムで使用されるディスクサイズは、information_schema.INNODB_TABLESPACESのallocation_sizeからinformation_schema.TABLESの(data_length + index_length)を引いたものに相当すると想定できますか?または...このスペースを使用している可能性のある他のものはありますか?

もしそうなら、ブロブをS3のファイルへのポインターに置き換えることで、多くのスペースを取り戻すことができるはずです。


また、この不一致は未割り当ての領域が原因である可能性もあると考えました。過去に多数の削除があった場合。ただし、ここではDATA_FREEとして表示されると思うので、無視できるようです。

mysql> SELECT      table_name AS `Table`,   round(data_free / 1024 / 1024) as 'Data free in MB',   round(((data_length + index_length) / 1024 / 1024), 2) `Size in MB`  FROM information_schema.TABLES  WHERE table_schema = 'prod_insti' AND table_name = 'workItemContentVersion';
+------------------------+-----------------+------------+
| Table                  | Data free in MB | Size in MB |
+------------------------+-----------------+------------+
| workItemContentVersion |               2 | 1398809.50 |
+------------------------+-----------------+------------+

これは急速に成長しているテーブルであり、削除が発生することを認識していなかったので、これは私には理にかなっています。他のテーブルで高いDATA_FREE値を探したところ、DATA_LENGTH値と同じ桁数のものが見つからなかったので、これは私の問題ではないと思います。

また、このテーブルでOPTIMIZE_TABLEを実行する必要があるかもしれないと思ったのですが、それが必要または役立つことを示す情報がわからないのです。異常に高いDATA_FREEカウントは、OPTIMIZE_TABLEを実行する必要があることを示していますか?

1
Alex
 SHOW TABLE STATUS LIKE 'workItemContentVersion';

おそらく、I_Sクエリから取得した1.4TBが得られます。しかし、それを試してみてください。

innodb_page_sizeの値は何ですか?通常は16384ですが、COMPRESSEDと2つの数値の差はほぼ正確に2倍です。

"Data_free"は、テーブル内のいくつかの "空き"スペースの1つだけを提供します。ですから、悲しいかな、OPTIMIZE TABLEをいつ実施するかを決定する適切な指標はありません。置き換えられない大量の削除など、まれな場合にのみ、OPTIMIZEを実行する価値があります。そして、1.4TB(または2.8TB)のテーブルには長い時間がかかります。

innodb_file_per_tableの設定は何ですか?それは1である方がいいです、さもなければ、最適化は物事を悪化させるだけです。それでも、クエリを実行するには、いくつかのTB=が必要です。

Data_freeの2MBは実際には異常に小さいです。私が目にするほとんどすべてのテーブルで、その数は4Mから7M(またはそれ以上)です。

データとPRIMARY KEYは、そのPKによって順序付けされた1つのBTreeに共存します。各セカンダリインデックスは個別のBTreeにあり、リーフの「行」にはPKが含まれています。

大きなブロブ(および大きなテキスト、そして時には大きなvarchar)は、上記のBTreeにはありません。他のいくつかのブロックではオフになっています。これを「オフレコストレージ」と呼ぶ人もいます。

COMPRESSEDは通常、わずか2倍の収縮でベンチマークされます。 (text/xml/code/etcを3倍に圧縮するほとんどの圧縮ルーチンとは異なります。)

OPTIMIZE TABLEは基本的にテーブルをコピーし、インデックスを再構築します。データBTreeの場合、これは比較的単純で、そのBTreeからほとんどの未使用のスペースを絞り出します。インデックスは縮小される場合とされない場合があります。私はそれらが再構築されたのではなく、コピーされたと思います。

テーブルのメンテナンス(列の追加、データ型の変更など)が必要な場合は、ALTERを実行することをお勧めします。 someの状況では、最適化作業を行います。さらに良いことに、ALGORITHM=COPYを使用すると、そのように強制されます。

Data_lengthにblobが含まれていることを望みますが、証明がありません。

削除は必ずしもData_freeに表示されるとは限りません。そのメトリックはブロックのみをカウントします。 BTreeはブロックの集まりです。 InnoDBは、削除後に隣接ブロックを結合しようとします。ただし、最高の状態では、各BTreeブロックは50%から100%でいっぱいで、平均69%です。これはnotがData_freeに反映されます。

したがって、たとえば、テーブルの3行ごとに削除した場合、Data_lengthとData_freeは変更されない可能性があります。各3から2を削除is一部のブロックを使用済みから解放に移動する可能性があります。

圧縮はブロックレベルです。そのため、buffer_poolは、多くのブロックの2つのコピー(圧縮されたコピーと圧縮されていないコピーの両方)を持つ傾向があります。つまり、ディスク領域は節約されますが、buffer_poolが影響を受けます。サーバーに負荷をかけるのではなく、クライアントで圧縮することを好みます。これにより、CPUの負荷が軽減され、多くの場合3倍になります。

短いテキスト/ブロブのある行の場合、そのデータはレコードに保存されます。つまり、オフレコストレージは大きな列用に予約されています。 (これはROW_FORMATによって異なります。これは、テーブルのCOMPRESSEDであると想定しています。)

1
Rick James