1. PartitionKey: Design for Scalability and Query Patterns
The PartitionKey determines how your data is distributed across storage nodes. Good partitioning avoids hotspots and keeps queries fast.
✔️ Best Practices
-
Group entities that you frequently query together
Azure Tables can only efficiently query within a partition. If you often query “all orders for a customer,” thenPartitionKey = CustomerIdis a strong choice. -
Avoid extremely large single partitions
A single partition can only scale so far. If you expect millions of entities in one partition, consider adding a secondary dimension, such as:CustomerId + MonthDeviceId + DateRegion + Category
-
Avoid extremely small partitions
Too many tiny partitions can slow down scans and increase overhead. -
Choose keys that evenly distribute load
If all writes go to the same partition (e.g.,PartitionKey = "Orders"), you create a hotspot. Spread writes across partitions.
✔️ Good PartitionKey examples
| Scenario | Good PartitionKey |
|---|---|
| IoT telemetry | DeviceId or DeviceId + Date |
| Multi-tenant SaaS | TenantId |
| Logging | Date (e.g., 2025-02-04) |
| E‑commerce orders | CustomerId or CustomerId + Year |
2. RowKey: Ensure Uniqueness and Fast Lookup
The RowKey uniquely identifies an entity within a partition. Azure Tables sort RowKeys lexicographically.
✔️ Best Practices
-
Make RowKey unique within the partition
Common patterns:- GUID
- Timestamp (inverted for newest-first)
- Natural key (OrderId, UserId, etc.)
-
Use RowKey to optimize query order
Because RowKeys are sorted, you can:- Store newest items first using a descending timestamp trick:
RowKey = (DateTime.MaxValue - timestamp).Ticks - Store items alphabetically or numerically for range queries.
- Store newest items first using a descending timestamp trick:
-
Keep RowKeys short
Long keys increase storage cost and slow down queries.
✔️ Good RowKey examples
| Scenario | Good RowKey |
|---|---|
| Logging | Inverted timestamp (RowKey = MaxTicks - Now.Ticks) |
| Orders | OrderId |
| IoT telemetry | Timestamp or sequence number |
| User profiles | UserId |
3. General Key Design Principles
✔️ Keep keys ASCII-safe
Avoid characters that require escaping (/, \, #, ?).
✔️ Keep keys predictable
You want to be able to compute the key without extra lookups.
✔️ Keep keys immutable
Changing keys means deleting and re‑inserting the entity.
✔️ Think about your query patterns first
Azure Tables are not relational. You design keys based on how you read data, not how you model it.
4. Common Patterns (with examples)
Pattern A: Time-series data
PartitionKey: DeviceId
RowKey: Inverted timestamp
- Fast “latest first” queries
- Even distribution across devices
Pattern B: Multi-tenant SaaS
PartitionKey: TenantId
RowKey: EntityId
- Easy to isolate tenant data
- Scales well
Pattern C: Event logs
PartitionKey: Date (e.g., 2025-02-04)
RowKey: GUID or timestamp
- Efficient daily queries
- Avoids giant partitions
5. Anti‑Patterns (Avoid These)
❌ PartitionKey = same value for all rows
Creates a massive hotspot.
❌ RowKey = random GUID when you need sorted queries
GUIDs destroy ordering.
❌ PartitionKey = GUID
You lose the ability to query groups of related data.
❌ Too many partitions (e.g., PartitionKey = GUID per row)
Makes range scans impossible.
Summary
PartitionKey
- Group related data
- Spread load
- Match your query patterns
- Avoid hotspots
RowKey
- Unique within partition
- Sorted for fast range queries
- Short and predictable
Together, they define your performance, scalability, and cost.
