CIデータベースに新しいテーブルを追加
パイプライン・データ・パーティショニング設計ブループリントでは、CIドメインの既存のテーブルをパーティショニングする方法を説明します。しかし、新しい機能のテーブルを追加する必要があります。これらのテーブルが、パーティショニングが必要なより大きなテーブルへの参照を保持することもあります。将来の作業を減らすために、パーティショニング可能なテーブルへのbelongs_to
関連付けを使用するすべてのテーブルは、最初からパーティショニングする必要があります。
新しいルーティング・テーブルの作成
データベースヘルパーを使って新しいテーブルと外部キーを作成する例を示します:
include Gitlab::Database::PartitioningMigrationHelpers
disable_ddl_transaction!
def up
create_table(:p_ci_examples, primary_key: [:id, :partition_id], options: 'PARTITION BY LIST (partition_id)', if_not_exists: true) do |t|
t.bigserial :id, null: false
t.bigint :partition_id, null: false
t.bigint :build_id, null: false
end
add_concurrent_partitioned_foreign_key(
:p_ci_examples, :p_ci_builds,
column: [:partition_id, :build_id],
target_column: [:partition_id, :id],
on_update: :cascade,
on_delete: :cascade,
reverse_lock_order: true
)
end
def down
drop_table :p_ci_examples
end
このテーブルはルーティングテーブルと呼ばれ、データを保持しません。データはパーティションに格納されます。
ルーティングテーブルを作るとき
- テーブル名は
p_
プレフィックスで始まる必要があります。すべてのクエリがルーティング・テーブルを経由し、パーティションに直接アクセスしないようにするためのアナライザがあります。 - それぞれの新しいテーブルには
partition_id
列が必要で、その値は関連するアソシエーションの値と等しくなければなりません。この例では、p_ci_builds
です。パイプラインに属するすべてのリソースは、同じpartition_id
の値を共有します。 - 主キーは、
id
によってのみ効率的に検索できるように、カラムをこのように並べる必要があります。 - 外部キー制約には、
ON UPDATE CASCADE
オプションを含める必要があります。これは、partition_id
値がパーティションの再バランスのために更新できる必要があるためです。
最初のパーティションを作成します。
通常、ブート時に最初のパーティションを作成するのはアプリケーションに依存します。しかし、CIテーブルのトラフィックが多く、ノード数が多いため、参照テーブルのロックを取得するのが難しい場合があります。その結果、デプロイ中にノードの起動に失敗することがあります。この失敗を防ぐには、アプリケーションの実行前にパーティションがすでに配置されていることを確認する必要があります:
disable_ddl_transaction!
def up
with_lock_retries do
connection.execute(<<~SQL)
LOCK TABLE p_ci_builds IN SHARE ROW EXCLUSIVE MODE;
LOCK TABLE ONLY p_ci_examples IN ACCESS EXCLUSIVE MODE;
SQL
connection.execute(<<~SQL)
CREATE TABLE IF NOT EXISTS gitlab_partitions_dynamic.ci_examples_100
PARTITION OF p_ci_examples
FOR VALUES IN (100);
SQL
end
end
パーティションはgitlab_partitions_dynamic
スキーマで作成されます。
パーティションを作成するときは
- パーティション名には
p_
という接頭辞をつけないこと。 -
partition_id
の開始値は100
です。
パーティション値のカスケード
パーティション値をカスケードするには、Ci::Partitionable
モジュールを使用する必要があります:
class Ci::Example < Ci::ApplicationRecord
include Ci::Partitionable
self.table_name = :p_ci_examples
self.primary_key = :id
belongs_to :build, class_name: 'Ci::Build'
partitionable scope: :build, partitioned: true
end
パーティションの管理
partition_id
が正しく伝播されることをテストするために使用されるため、モデルはPARTITIONABLE_MODELS
リストに含まれていなければなりません。
これがない場合、partitioned: true
を指定すると、最初のパーティションが作成されます。また、モデルはpostgres_partitioning.rb
イニシャライザーに登録する必要があります。