VillageSQL is a drop-in replacement for MySQL with extensions.
All examples in this guide work on VillageSQL. Install Now →
When Partitioning Helps
Partition pruning delivers real gains when:- The table is too large to fit in the buffer pool and queries consistently filter on the partition key
- You regularly drop old data —
ALTER TABLE t DROP PARTITION p_oldis instant vs. a slow DELETE
- Queries don’t filter on the partition key (all partitions must be scanned)
- The table fits comfortably in memory
- You’re trying to replace proper indexing — a good index on a non-partitioned table often outperforms a partitioned table without matching indexes
RANGE Partitioning
Rows are assigned to partitions based on whether the partition key falls within a range. The most common use case is date-based archival.MAXVALUE partition to catch rows that don’t fit any defined range. Without it, inserts outside the defined ranges fail with an error.
Add a new partition:
LIST Partitioning
Rows are assigned based on exact values in the partition key.LIST COLUMNS (MySQL 5.5+) for string columns — LIST alone only supports integer expressions.
HASH and KEY Partitioning
HASH and KEY distribute rows evenly across a fixed number of partitions. They don’t support partition pruning by value but can improve concurrent write throughput by spreading rows across partitions.
Partition Pruning
Pruning only activates when theWHERE clause filters directly on the partition expression. With RANGE COLUMNS (created_at), filtering on created_at prunes correctly:
EXPLAIN and check the partitions column:
partitions shows only one or a few partition names, pruning is working. If it shows all partitions, the filter isn’t being applied.
Partitioning Constraints
- Every unique key (including the primary key) must include all columns in the partitioning expression. If you want to partition by
created_at, every unique key must containcreated_at— you can’t add a partition to a table with a standalonePRIMARY KEY (id)unless you first change it toPRIMARY KEY (id, created_at). FOREIGN KEYconstraints are not supported on partitioned tables in MySQL.- A table can have a maximum of 8192 partitions (MySQL 8.0+).
Partitioning vs Indexing
| Partitioning | Indexing | |
|---|---|---|
| Best for | Range-based data pruning, archival drops | Point lookups, range scans on any column |
| Requires schema change | Yes | Yes (ALTER TABLE ADD INDEX) |
| Speeds up any query | Only queries filtering on partition key | Any query using indexed columns |
| Drops old data | Instant (DROP PARTITION) | Requires DELETE + index maintenance |
| Foreign keys | Not supported | Supported |
Frequently Asked Questions
Can I partition an existing table?
Yes, withALTER TABLE:
How do I check which partition a row is in?
EXPLAIN PARTITIONS with a WHERE clause matching that row.
Troubleshooting
| Problem | Solution |
|---|---|
ERROR 1526: Table has no partition for value | RANGE or LIST has no matching partition — add a MAXVALUE partition for RANGE or handle the missing value in LIST |
ERROR 1503: A PRIMARY KEY must include all columns in the table's partitioning function | Add the partition key column to the primary key definition |
| Partition pruning not occurring | Check EXPLAIN partitions column; ensure the WHERE clause uses the partition column directly, not wrapped in a function |
ALTER TABLE DROP PARTITION returns an error | Table must be RANGE or LIST partitioned — HASH and KEY partitions can’t be dropped individually |
| Performance worse after partitioning | Queries may not be pruning — verify with EXPLAIN, and check that indexes exist on each partition for the columns used in WHERE |

