Programmingデータアーキテクト

大きなテーブルをスケールさせるためのSQLにおける効率的な負荷分散(シャーディング/パーティショニング)を実現する方法を説明してください。パーティショニングとシャーディングの違いは何ですか?そして、どのような落とし穴がありますか?

Hintsage AIアシスタントで面接を突破

回答

大きなデータ量の分散は、主に二つの方法で達成されます:

  1. パーティショニング(partitioning): 同一データベース内の一つのテーブルを、通常は日付または値の範囲に基づいてセグメント(partition)に論理的に分割します。これにより、個別のセクションに対して迅速に操作を行うことができ、検索が速くなり、メンテナンスが容易になります。

  2. シャーディング(sharding): 特定のアルゴリズムに基づいてデータを複数のDB/サーバーに物理的に分割します。テーブルは実際に異なるクラスタに複製され、それぞれがそのセグメントのデータを含みます。

パーティショニングの利点は、リクエストのルーティングに別のビジネスロジックを維持する必要がなく、すべてがアプリケーションに対して「透明に」行われることです。欠点は、一つのDBMSの能力に制限されることです。

シャーディングは水平スケーリングを提供します(制限はサーバーの数だけです)が、複雑な同期、ルーティング、および「シャード間」リクエストの処理を必要とします。

例(PostgreSQL, range-partitioning):

-- ベーシックなパーティショニングテーブル CREATE TABLE orders ( id SERIAL PRIMARY KEY, customer_id INT, order_date DATE ) PARTITION BY RANGE (order_date); CREATE TABLE orders_2023 PARTITION OF orders FOR VALUES FROM ('2023-01-01') TO ('2024-01-01');

だましの質問

質問: 基本テーブルをブロックせずに、パーティション間で行を「オンザフライ」で移動することはできますか?

回答: ほとんどのDBMSでは、パーティション間での行の移動は削除と挿入に相当します。このような操作は行やテーブルそのものをブロックする可能性があり、特にトリガーや外部キーが関与する場合には注意が必要です。これは、大量のデータをセクション間で「ロールバック」する際に考慮する必要があります。

例:

-- ALTER TABLE ... MOVE PARTITION は、一般的にロックに特別な注意を必要とします。負荷の少ない時間に行うのが良いです。

このテーマの詳細を知らないことによる実際のエラーの例


ストーリー 1: プロジェクトでは、すべてのパーティションに対して同時に分析レポートを構築していましたが、数千のセクションを持つセクショニングされたテーブルが巨大なクエリ実行計画を生成していることを考慮していませんでした。その結果、実行時間とサーバーの負荷が急増しました。解決策:リクエストの実際のビジネス軸に対応するパーティションの数を増やし、スキャン計画を最適化しました。


ストーリー 2: シャーディングを追加する際、シャード間での識別子の一意性を考慮しませんでした。そのため、しばしばシャード間集約時にキーの競合が発生しました。


ストーリー 3: 古くなったパーティションを自動的にアーカイブするロジックが、外部リンクの再確認なしにそれらを削除したため、他のテーブルとのリンクを失い、一部の「生きた」データを失いました。その後、パーティション削除のロジック全体を整合性テストのマルチテストに書き換えました。