Vitess’s vertical sharding feature lets you move tables from one keyspace to another, typically to consolidate or distribute data based on access patterns.

Let’s see this in action. Imagine we have a user_keyspace with tables users, user_profiles, and user_settings. We want to move user_profiles and user_settings to a new profile_keyspace for better isolation.

Here’s a simplified vschema.json before the move:

{
  "sharded": true,
  "vindexes": {
    "user_id_vdx": {
      "type": "numeric_vdx",
      "owner": "users"
    }
  },
  "tables": {
    "users": {
      "key_columns": {
        "user_id": "user_id_vdx"
      }
    },
    "user_profiles": {
      "key_columns": {
        "user_id": "user_id_vdx"
      }
    },
    "user_settings": {
      "key_columns": {
        "user_id": "user_id_vdx"
      }
    }
  }
}

And here’s the vschema.json for the target profile_keyspace (initially empty of these tables):

{
  "sharded": true,
  "vindexes": {
    "user_id_vdx": {
      "type": "numeric_vdx",
      "owner": "user_profiles"
    }
  },
  "tables": {
    "user_profiles": {
      "key_columns": {
        "user_id": "user_id_vdx"
      }
    },
    "user_settings": {
      "key_columns": {
        "user_id": "user_id_vdx"
      }
    }
  }
}

The core idea is to use the MoveTables workflow. Vitess handles the heavy lifting: it creates the schema in the target keyspace, streams data from the source to the target, synchronizes changes, and finally switches over traffic. The vtctlclient command is your entry point.

The workflow typically involves these steps:

  1. Create the target keyspace and tables: Ensure the profile_keyspace exists and has the correct schema for user_profiles and user_settings. This is often done via a vtctlclient ApplySchema command.
  2. Initiate the MoveTables workflow: Use vtctlclient MoveTables to tell Vitess you want to move specific tables. You’ll specify the source and target keyspaces, and the tables to move.
  3. Monitor the workflow: Vitess will create a set of "move_tables" resharding jobs. You can monitor their progress using vtctlclient WorkflowStatus. This involves data streaming and replication.
  4. Complete the workflow: Once the data is synchronized and traffic can be safely switched, you’ll use vtctlclient CompleteMoveTables to finalize the migration. This updates the vschema and disconnects the old tables.

Let’s look at the vtctlclient commands.

First, create the profile_keyspace if it doesn’t exist. You’d typically do this via vtctlclient CreateKeyspace profile_keyspace. Then, apply the schema for the tables you’re moving into profile_keyspace. Assuming you have a schema file profile_schema.sql:

vtctlclient --server <vtctl-host>:<vtctl-port> ApplySchema -keyspace profile_keyspace -sql '
CREATE TABLE user_profiles (
  user_id BIGINT,
  profile_data JSON,
  PRIMARY KEY(user_id)
);
CREATE TABLE user_settings (
  user_id BIGINT,
  setting_name VARCHAR(255),
  setting_value VARCHAR(255),
  PRIMARY KEY(user_id, setting_name)
);
'

Now, initiate the move. This command tells Vitess to start the background process of migrating user_profiles and user_settings from user_keyspace to profile_keyspace.

vtctlclient --server <vtctl-host>:<vtctl-port> MoveTables -source_keyspace user_keyspace -target_keyspace profile_keyspace user_profiles,user_settings

After running this, Vitess spins up a set of resharding jobs that handle the data migration. You can monitor the progress:

vtctlclient --server <vtctl-host>:<vtctl-port> WorkflowStatus move_tables-user_keyspace-profile_keyspace

You’ll see stages like "Resmearing", "ResmearerOnline", "Materialize", and "MaterializeOnline". Once the data is caught up, you’ll see "ReadyToComplete".

Finally, you complete the move. This is the point where Vitess updates the vschema to point to the new tables in profile_keyspace and stops serving reads/writes for these tables from user_keyspace.

vtctlclient --server <vtctl-host>:<vtctl-port> CompleteMoveTables -source_keyspace user_keyspace -target_keyspace profile_keyspace user_profiles,user_settings

The vschema in user_keyspace will be updated to remove these tables, and the vschema in profile_keyspace will reflect their presence.

The mechanism relies on Vitess’s resharding infrastructure. It essentially treats this as a resharding operation where a subset of tables is being "moved" to a new destination (which might be a new keyspace entirely, or a new set of shards within the same keyspace if you were doing horizontal resharding). The MoveTables workflow orchestrates the creation of temporary resharding jobs that read from the source, write to the target, and keep the data in sync via VReplication.

The most surprising part of MoveTables is how it handles FOREIGN KEY constraints. If you have foreign keys referencing tables that are not being moved, Vitess will generally disallow the operation or require careful manual intervention. It assumes that all related tables that participate in referential integrity should be moved together or that the foreign keys are being dropped. This is because maintaining cross-keyspace foreign keys is complex and often inefficient.

After successfully completing a MoveTables operation, the next logical step is often to clean up the now-empty tables in the source keyspace, or to address any remaining tables in the source keyspace that might now have different access patterns.

Want structured learning?

Take the full Vitess course →