500万行の単一テーブルはデータベースシャーディングとテーブルシャーディングが必要でしょうか？

> 本記事は[こちらのブログ](https://www.alibabacloud.com/blog/does-a-single-table-with-5-million-rows-need-database-sharding-and-table-sharding_601922?spm=a2c65.11461433.0.0.4ee35355uk6pGa)を参考にしています。
> 翻訳にはアリババクラウドの[ModelStudio](https://www.alibabacloud.com/en/product/modelstudio)([Qwen](https://www.alibabacloud.com/en/solutions/generative-ai/qwen))を使用しております。

<div class="wrap-main-left-article markdown-body">

## 1. データベースシャーディングとテーブルシャーディングの従来の課題
ビジネスアーキテクチャ設計において、最も重要な側面の一つはデータベースモデリングです。単一マシンの計算およびストレージ容量に制限があるため、多くのアーキテクトはミドルウェアや他の方法を使用して大規模なテーブルを分割し、複数のデータベースやテーブルにデータを分散させ、最終的にシャーディングによってリソースのスケーラビリティを達成しなければなりません。そのため、MySQLエコシステムではしばしば「単一のテーブルは500万行を超えない」と言われています。一般的に、シャーディングソリューションは以下の問題に対処します：
- 不足しているローカルストレージ
- 不足している計算能力
- 大規模なテーブルの運用上の課題

データ量が増加すると、O&Mチームはデータ分割を検討し、ビジネスの安定性を確保する必要があります。データベースシャーディングとテーブルシャーディングの互換性の問題により、ビジネスコードの変更が必要になります。開発チームはアーキテクチャの変換に参加し、新しいデータベースとテーブル構造に適応するためのSQLステートメントを再記述する必要があります。ビジネスチームはビジネスの成長に集中しており、ほとんどの場合、システム分割にはほとんど時間が割けません。その結果、システム分割は最終的に実施されるまで延期され、この期間中、全体的なシステムの安定性は常に危険にさらされます。

テーブルに500万行を超えないというルールは、MySQLエコシステムに深い歴史的根拠があります。リソース面では、初期のサーバーのI/O容量が比較的低かったため、単一のテーブルが大きすぎるとBツリーインデックスの高さが増加し、I/O問題が発生しました。また、ディスク容量も限られていたため、ストレージの制限とバックアップスペースが懸念されました。運用面では、古いバージョンのMySQL（V5.5以前）はオンラインDDLをサポートしていなかったため、大規模なテーブルのメンテナンス時にサービス中断が発生することがありました。

クラウドネイティブデータベースであるAlibaba Cloud ApsaraDBのPolarDBは、共有分散ストレージシステムを使用しており、大規模なテーブルの処理に大幅に強力な機能を提供します。多くの従来のデータベースシャーディングとテーブルシャーディングのシナリオはもう適用できません。PolarDBパブリッククラウドでは、多くのユーザーが単一のテーブルで10 TB以上または10億行以上のデータを持っています。このような単一のテーブルに関連するデータに対してデータベースシャーディングとテーブルシャーディングを行うのは非常に複雑です。したがって、必要でない限り、最初から過度な最適化を行わないことをお勧めします。

## 2. PolarDBでの大規模テーブルの最適化プラクティス
### 2.1 大規模な弾性ストレージを提供
急速な成長期に多くのビジネスは、計算ボトルネックに達したわけではなく、大量のデータセットのストレージ容量が単一インスタンス内で制限に達したため、データ分割が必要であることに気づきました。これは、初期設計が大規模なデータ使用パターンを考慮していないか、ビジネスロジックがデータのクリーンアップやアーカイブを許可していない場合によく発生します。<a href="https://www.alibabacloud.com/product/polardb-for-mysql?spm=a3c0i.14509290.7580098850.1.63e07b8dPBdRcl" target="_blank">PolarDB for MySQL</a>は、コンピュート-ストレージ分離アーキテクチャと分散共有ストレージを使用しています。従来のスタンドアロンMySQLインスタンスと比較して、分散共有ストレージは単一のPolarDB for MySQLクラスターで最大500 TBのデータを保存できます。大量のストレージ空間を持つことで、ユーザーはディスク容量の制限やスケーリングの問題を心配する必要がなく、ビジネス要件の設計に集中することができます。データベースやテーブルへの分割は不要であり、これによりビジネスシステムの複雑さが大幅に軽減されます。

![1](https://yqintl.alicdn.com/b6185c09608b7b7f173e3c2cdd98698c4b4d89cb.png)

### 2.2 計算能力の最適化
スタンドアロンインスタンスを制限する最大の要素の一つは、大規模テーブルのパフォーマンスです。大規模テーブルがデータベース操作のボトルネックにならないようにするために、PolarDBは広範な研究と検証を行いました。大規模テーブルのデータ挿入シナリオにおける痛点を解決するために、各モジュールがボトルネックを引き起こすメカニズムを調査し、それに応じて最適化しました。ベンチマークテストと実際のビジネスシナリオを通じて、最大10倍のパフォーマンス向上を達成できます。

#### 2.2.1 インデックス並列制御の最適化
<a href="https://www.alibabacloud.com/product/polardb-for-mysql?spm=a3c0i.14509290.7580098850.1.63e07b8dPBdRcl" target="_blank">PolarDB</a>は、単一インスタンスの大規模インデックスロックを最適化し、並列分割を可能にするPolarインデックスを革新的に提案しました。これにより、高並列アクセス時の競合オーバーヘッドが減少します。実際のオンラインビジネスシナリオでは、パフォーマンスが3倍向上し、TPCCシナリオではパフォーマンスが11倍向上します。

![2](https://yqintl.alicdn.com/cff3312b773c4d606b45262abe56971877126ed1.png)

#### 2.2.2 テーブルファイル拡張の最適化
データが継続的に書き込まれるため、テーブルファイルを拡張する必要があります。高頻度のデータ挿入は、テーブルスペースの拡張頻度も増加させます。MySQLでは、テーブルスペースの拡張はリソース集約型の操作です。したがって、高頻度の拡張操作はトランザクションの実行パフォーマンスに影響を与えます。大規模テーブルのデータ挿入シナリオでのファイル拡張のオーバーヘッドを削減するために、PolarDBは自社開発の分散ファイルシステムを利用します。テーブルファイルの拡張プロセス中にファイルシステムメタデータを最小限に修正することで、ロックオーバーヘッドがボトルネックになることを防ぎます。これにより、大量のデータ書き込みシナリオでのPolarDBのパフォーマンスが大幅に向上します。

![3](https://yqintl.alicdn.com/a8ed16a2d8926543628399c1a23d0e44bcc70212.png)

#### 2.2.3 Redoログ書き込みの最適化
高負荷の挿入は必然的に大量のRedoログを生成します。トランザクションの耐久性を確保するためには、すべてのRedoログがディスク上に保存された後にのみトランザクションを返却できます。したがって、Redoログ書き込みの遅延とスループットは直接データベースパフォーマンスに影響します。PolarDBは、大規模テーブルの大量のRedoログをディスクに書き込む痛点を解決するために、並列Redoログ書き込みメカニズムを革新的に導入しました。現在、Redo
# DDL操作の実行効率向上

次の図は、並列DDL機能を有効にした後、INT型のbフィールドに対する二次インデックスを作成するDDL操作の実行効率がどのように向上したかを示しています。異なる数の並列スレッドを使用しています。結果によると、32スレッドを有効にすると最大2000%のパフォーマンス向上が達成できます。

![8](https://yqintl.alicdn.com/33e74cee766131a9f5feb97f09bd701615e7c5d6.png)
**異なる数の並列スレッドでのDDLパフォーマンス改善の比較**

## 2.3.2 セカンダリレベルのDDL（フィールドの追加または変更）

通常、テーブルに列を追加するには、テーブル全体を再構築する必要があります。これは大量のシステムリソースを消費します。PolarDB for MySQLは、即時ADD COLUMN機能をサポートしています。列を追加する際には、既存のデータではなくテーブル定義のみを変更する必要があるため、テーブルのサイズに関わらず瞬時に列を追加することができます。テーブルのサイズに関わらず、数秒で列を追加することができます。

![9](https://yqintl.alicdn.com/1bf7eab3a0ecb19d8aae1011e0880ef66d47cbc0.png)

## 2.3.3 数秒で文字セット変換

UTF-8コードセットは一般的に使用されるコードセットです。MySQL Community Editionでは、デフォルトでutf8mb3文字セットがUTF-8エンコーディング形式として使用されます。この文字セットは、1文字あたり最大3バイトを使用します。絵文字などの情報を保存する場合、utf8mb4文字セットに変換する必要があるかもしれません。通常、文字セットの変換にはテーブルの再構築が必要であり、時間がかかり、ビジネスに大きな影響があります。PolarDB for MySQLは、utf8mb3からutf8mb4への数秒での変換をサポートしています。この機能により、utf8mb3文字セットをutf8mb4文字セットに簡単に変更することができます。sql
ALTER TABLE tablename MODIFY COLUMN test_column varchar(60) CHARACTER SET utf8mb4, ALGORITHM = INPLACE;

上記のステートメントを実行した後に以下のようなエラーメッセージが返された場合は、現在の操作がin-placeアルゴリズムを使用して実行できないことを示します。
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.

この場合、使用制限を慎重に確認することをお勧めします。ALGORITHMをDEFAULTに設定するか、指定しない場合、PolarDBは列の文字セットを変更するために最も速いアルゴリズムを選択します。

例：sql
ALTER TABLE tablename MODIFY COLUMN test_column varchar(60) CHARACTER SET utf8mb4, ALGORITHM = DEFAULT;
ALTER TABLE tablename MODIFY COLUMN test_column varchar(60) CHARACTER SET utf8mb4;

効果：テーブルのサイズに関わらず、utf8mb3からutf8mb4への文字セット変換を数秒で完了できます。

## 2.3.4 SaaS機能：TRUNCATE/DROP TABLEの高速化

MySQL Community 5.7でTRUNCATE TABLEおよびDROP TABLEステートメントを実行すると、バッファプール全体がスキャンされ、テーブルスペースに対応するすべてのデータページがLRUリストとFLUSHリストから削除されます。バッファプールが大きい場合、このプロセスには時間がかかります。PolarDBは、DDLステートメントのバッファプール管理メカニズを最適化し、バッファプールのスキャン効率とTRUNCATE TABLEおよびDROP TABLEステートメントの実行効率を向上させています。

手順：
`loose_innodb_flush_pages_using_space_id` パラメータをONに設定して、この機能を有効にします。

効果：
異なる仕様のクラスターについて、t1とt2テーブルでTRUNCATE TABLEステートメントを実行するために必要な時間（秒）を、高速TRUNCATE/DROP TABLE機能を有効にした場合と無効にした場合で記録します。この例では、t1テーブルに8,196行のデータを挿入して小規模テーブルのTRUNCATE操作をシミュレートし、t2テーブルに2,097,152行のデータを挿入して大規模テーブルのTRUNCATE操作をシミュレートします。以下の表に実行結果を示します。

![10](https://yqintl.alicdn.com/b3b978e8c7d41d4825be64f6b2a1069d301df0cb.png)

上記の表は、高速TRUNCATE/DROP TABLE機能を有効にすることで、TRUNCATE TABLEステートメントの実行効率が大幅に向上することを示しています。

## 2.3.5 ビジネスアバランチを避ける：非ブロッキングDDL

ブロッキングDDLステートメントが提出され、それが影響を与えるテーブルに未コミットのトランザクションやクエリがある場合、DDLステートメントはMDL-Xロックを待機し続けます。DDLステートメントが待機している間でも、同じテーブルのデータを操作する新しいトランザクションは提出される可能性があります。しかし、PolarDBのMDL-Xロックは最高優先度を持っているため、新しいトランザクションはこのブロッキングDDLステートメントが完了するまで待機しなければなりません。その結果、接続が混雑し、ビジネスシステム全体に影響を与える可能性があります。これを解決するために、PolarDBではDDL操作用の非ブロッキングDDL機能を有効にすることができます。この機能を有効にすると、DDLステートメントのロックポリシーはツール（gh-ost / DMS lock-free change）と同じになります。これにより、ビジネスに対してロックフリー/ロスレスなパフォーマンスを達成できます。さらに、DDLプロセスがカーネルにネイティブであるため、PolarDBのパフォーマンスは周辺ツールよりも大幅に優れています。この機能を有効にすると、DDL操作はカーネルの高いパフォーマンスを維持しつつ、周辺ツールを使用した場合に類似するロスレスな特徴を持つことができます。これにより、DDL操作がビジネスに与える影響が大幅に減少します。

手順：
`loose_polar_nonblock_ddl_mode` パラメータを使用して非ブロッキングDDL機能を有効にします。この機能を有効にすると、ピーク時のビジネス時間帯でもDDLステートメントを実行できます。DDLがロックを取得できなくても、ビジネスには影響を与えません。

効果：
1. 非ブロッキングDDLステートメントが無効の場合、TPSはゼロに低下し、長時間ゼロのままになります。デフォルトのタイムアウトは31,536,000秒で、ビジネスに深刻な影響を与えます。
   ![11](https://yqintl.alicdn.com/d11674eeb23e7ec68e4e354cb6f4519ddebf80e1.png)

2. 非ブロッキングDDLステートメントが有効の場合、TPSは周期的に低下しますが、ゼロにはなりません。ロック待ちはビジネスにわずかな影響しか与えず、システムの安定性が確保されます。
   ![12](https://yqintl.alicdn.com/16a0b4f538aa92aa437cf22ac2e21d01d4ff5f7f.png)

3. gh-ostを使用してテーブルスキーマを変更する場合、TPSは周期的にゼロに低下します。この場合、切り替えステップでの一時的なテーブルロックにより、ビジネスに深刻な影響が及ぼされます。
   ![13](https://yqintl.alicdn.com/b92cb4f90dd4