Pick Your Vitess Sharding Key Before You Write the Query
Choose a Vitess sharding key based on query patterns, then verify routing with vtctl before resharding becomes necessary.
28 Dec 2025, 21:40 UTC

The sharding key you pick today controls tomorrow's queries
You are moving a busy orders table out of a single MySQL instance and into Vitess. The table has customer_id, order_date, and status. It is tempting to shard on customer_id because most application traffic looks up a customer's orders. But your analytics dashboard runs reports by order_date. If customer_id is the sharding key, a query filtered only by order_date cannot be directed to one shard. Vitess must either send it to every shard or reject it, depending on how the workload is configured. That decision is encoded in the VSchema, and changing it later means resharding.
The useful takeaway: choose the sharding key from the queries that must remain fast and single-shard, then verify the routing with vtctl before you build around it.
How VTGate uses the VSchema to route a query
Vitess splits a keyspace into shards. A keyspace is the logical database; a shard is a physical MySQL subset holding a range of data. The VSchema is the configuration that tells VTGate which table lives in which keyspace and which column is the sharding key. VTGate is the proxy layer that parses incoming SQL. VTTablet is the process that sits in front of each MySQL instance and executes the routed query.
When a query arrives, VTGate extracts the sharding key from the WHERE clause, applies the configured vindex, and sends the query to the target shard. A vindex is a function that maps a sharding key value to a shard. A hash vindex spreads values evenly across shards using consistent hashing. A lookup vindex uses a separate mapping table, which is useful when the sharding key is not numeric or when the application controls which shard a row belongs to.
Worked example: routing an orders query
Suppose the orders table is sharded by customer_id using a hash vindex. The VSchema fragment might look like this:
{
"sharded": true,
"vindexes": {
"customer_hash": {
"type": "hash"
}
},
"tables": {
"orders": {
"columnVindexes": [
{
"column": "customer_id",
"name": "customer_hash"
}
]
}
}
}
A query such as:
SELECT * FROM orders WHERE customer_id = 42;
causes VTGate to hash 42, identify the destination shard, and forward the query to the VTTablet for that shard only. A query without customer_id, such as:
SELECT * FROM orders WHERE order_date = '2026-11-01';
has no sharding key to route on. Vitess may run it as a scatter query against every shard in the keyspace, or return an error if the workload is configured to reject unsharded reads. Either outcome is more expensive than a single-shard lookup.
Check the deployed VSchema
Run this from a machine that can reach the Vitess cluster:
vtctl GetVSchema <keyspace>
Where to run: any host with the vtctl binary and network access to the Vitess topology server. Permissions: read access to the Vitess topology; no MySQL superuser privileges are required for this read-only check. Placeholder: replace <keyspace> with your keyspace name, such as commerce. Expected check: the output lists the tables, columnVindexes, and vindex types. Risk: none; this is a read-only diagnostic.
Trade-off: even distribution is not the same as useful distribution
A hash vindex prevents hotspots by spreading rows randomly, but it also means you cannot efficiently query by a related column unless that column is the sharding key. A lookup vindex gives you control over placement, but adds a mapping table that must be kept consistent and can become its own bottleneck. Cross-shard joins and transactions are not atomic in Vitess, so a sharding key that forces frequent cross-shard operations can create consistency and operational problems.
Changing the sharding key after launch requires horizontal resharding: copying data to new shards, serving dual traffic, and cutting over with Vitess orchestration tools. Treat the initial VSchema as a long-term decision.
Verify before you commit
After applying a VSchema change, confirm routing rather than assuming it:
- Run
vtctl GetVSchema <keyspace>and confirm the column and vindex match your intent. - Enable VTGate query logging and run a representative query with and without the sharding key.
- Confirm the query with the sharding key reaches one tablet, while the query without it either scatters to all shards or is rejected, matching your workload policy.
Spin up the official Vitess local cluster example, insert rows with different sharding key values, and observe tablet distribution across shards to validate the behavior in a non-production environment.
Closing
Your sharding key should be chosen by the queries that cannot afford to scatter, not by the column that looks unique. Inspect the VSchema with vtctl, test routing with real query shapes, and treat resharding as a major operation rather than a routine schema change.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.