Skip to content

Add swap_primary_key database helper

Ref: #374743 (closed)

What does this MR do and why?

This MR adds a new migration helper method to swap primary key using a predefined index easily.

Why do we need this?

This is required in order to partition a table, the partition key must be include in the primary key.

It was brought up in !97926 (comment 1107227533) that we need to change the primary key of a table we are currently partitioning ci_builds_metadata.

This MR simplifies the process to swap the primary key.

Fake migration test

class SwapPrimaryKey < Gitlab::Database::Migration[2.0]
  disable_ddl_transaction!

  TABLE_NAME = :ci_builds_metadata
  PRIMARY_KEY = :ci_builds_metadata_pkey
  OLD_INDEX_NAME = :index_ci_builds_metadata_on_id_unique
  NEW_INDEX_NAME = :index_ci_builds_metadata_on_id_partition_id_unique

  def up
    swap_primary_key(TABLE_NAME, PRIMARY_KEY, NEW_INDEX_NAME)
  end

  def down
    add_concurrent_index(TABLE_NAME, :id, unique: true, name: OLD_INDEX_NAME)
    add_concurrent_index(TABLE_NAME, [:id, :partition_id], unique: true, name: NEW_INDEX_NAME)

    unswap_primary_key(TABLE_NAME, PRIMARY_KEY, OLD_INDEX_NAME)
  end
end
Database changes
ci: == 20220922140645 SwapPrimaryKey: migrating ===================================
ci: -- transaction_open?()
ci:    -> 0.0000s
ci: -- quote_table_name(:ci_builds_metadata)
ci:    -> 0.0000s
ci: -- quote_column_name(:ci_builds_metadata_pkey)
ci:    -> 0.0000s
ci: -- execute("ALTER TABLE \"ci_builds_metadata\" DROP CONSTRAINT \"ci_builds_metadata_pkey\" CASCADE\n")
ci:    -> 0.0009s
ci: -- rename_index(:ci_builds_metadata, :index_ci_builds_metadata_on_id_partition_id_unique, :ci_builds_metadata_pkey)
ci:    -> 0.0008s
ci: -- quote_table_name(:ci_builds_metadata)
ci:    -> 0.0000s
ci: -- quote_table_name(:ci_builds_metadata_pkey)
ci:    -> 0.0000s
ci: -- quote_table_name(:ci_builds_metadata_pkey)
ci:    -> 0.0000s
ci: -- execute("ALTER TABLE \"ci_builds_metadata\" ADD CONSTRAINT \"ci_builds_metadata_pkey\" PRIMARY KEY USING INDEX \"ci_builds_metadata_pkey\"\n")
ci:    -> 0.0011s
ci: == 20220922140645 SwapPrimaryKey: migrated (0.0163s) ==========================

------------------------ROLLBACK------------------------------

ci: == 20220922140645 SwapPrimaryKey: reverting ===================================
ci: -- transaction_open?()
ci:    -> 0.0000s
ci: -- index_exists?(:ci_builds_metadata, :id, {:unique=>true, :name=>:index_ci_builds_metadata_on_id_unique, :algorithm=>:concurrently})
ci:    -> 0.0056s
ci: -- execute("SET statement_timeout TO 0")
ci:    -> 0.0001s
ci: -- add_index(:ci_builds_metadata, :id, {:unique=>true, :name=>:index_ci_builds_metadata_on_id_unique, :algorithm=>:concurrently})
ci:    -> 0.0016s
ci: -- execute("RESET statement_timeout")
ci:    -> 0.0001s
ci: -- transaction_open?()
ci:    -> 0.0000s
ci: -- index_exists?(:ci_builds_metadata, [:id, :partition_id], {:unique=>true, :name=>:index_ci_builds_metadata_on_id_partition_id_unique, :algorithm=>:concurrently})
ci:    -> 0.0020s
ci: -- add_index(:ci_builds_metadata, [:id, :partition_id], {:unique=>true, :name=>:index_ci_builds_metadata_on_id_partition_id_unique, :algorithm=>:concurrently})
ci:    -> 0.0011s
ci: -- transaction_open?()
ci:    -> 0.0000s
ci: -- quote_table_name(:ci_builds_metadata)
ci:    -> 0.0000s
ci: -- quote_column_name(:ci_builds_metadata_pkey)
ci:    -> 0.0000s
ci: -- execute("ALTER TABLE \"ci_builds_metadata\" DROP CONSTRAINT \"ci_builds_metadata_pkey\" CASCADE\n")
ci:    -> 0.0008s
ci: -- rename_index(:ci_builds_metadata, :index_ci_builds_metadata_on_id_unique, :ci_builds_metadata_pkey)
ci:    -> 0.0003s
ci: -- quote_table_name(:ci_builds_metadata)
ci:    -> 0.0000s
ci: -- quote_table_name(:ci_builds_metadata_pkey)
ci:    -> 0.0000s
ci: -- quote_table_name(:ci_builds_metadata_pkey)
ci:    -> 0.0000s
ci: -- execute("ALTER TABLE \"ci_builds_metadata\" ADD CONSTRAINT \"ci_builds_metadata_pkey\" PRIMARY KEY USING INDEX \"ci_builds_metadata_pkey\"\n")
ci:    -> 0.0004s
ci: == 20220922140645 SwapPrimaryKey: reverted (0.0241s) ==========================
Indexes:
-     "ci_builds_metadata_pkey" PRIMARY KEY, btree (id)
+     "ci_builds_metadata_pkey" PRIMARY KEY, btree (id, partition_id)

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Max Orefice

Merge request reports

Loading