# Environment Sizing

> Recommended infrastructure sizing for Salesforce -> S3 -> TiDB Cloud Essential baseline build, based on measured staging data volume.

## Purpose

This document captures:

- the current measured staging data volume
- the largest tables relevant to migration planning
- two infrastructure sizing options:
  - a cost-sensitive baseline option
  - a safer headroom option

These recommendations are for the pre-production baseline-build workflow described in `SALESFORCE_DATA_MIGRATION.md`, not for a final production cutover design.

This document assumes TiDB Cloud **Essential**, not TiDB Cloud Dedicated.

---

## Measurement Source

Measured on: `2026-05-16 18:15:01 CST`

Source environment:

- host: `gateway01.us-east-1.prod.aws.tidbcloud.com`
- database: `nexuscrm`
- purpose: current staging dataset used as the closest available approximation of real online business data volume
- region assumption for pricing: `AWS us-east-1` / `N. Virginia (us-east-1)`

Measurement method:

- direct SQL count by object table
- `information_schema.tables` for table size estimates
- `SUM(ContentSize)` from `contentversion` for attachment payload size

---

## Current Measured Data Volume

### Core object counts

| Object | Record Count |
|--------|-------------:|
| Lead | 370,772 |
| CampaignMember | 672,321 |
| Task | 253,599 |
| org__c | 132,220 |
| Account | 3,307 |
| Contact | 7,067 |
| Opportunity | 3,568 |
| Quote | 927 |
| Contract | 499 |
| Campaign | 1,960 |
| Event | 1,191 |
| Product2 | 71 |
| Pricebook2 | 2 |
| PricebookEntry | 184 |

### Identity / access-related counts

| Object | Record Count |
|--------|-------------:|
| User | 319 |
| UserRole | 43 |
| Profile | 48 |
| PermissionSet | 188 |
| PermissionSetAssignment | 878 |
| ObjectPermissions | 15,338 |
| FieldPermissions | 420,615 |
| Group | 730 |
| GroupMember | 173 |
| RecordType | 50 |

### L2 custom object counts

| Object | Record Count |
|--------|-------------:|
| org__c | 132,220 |
| invoice_collection__c | 7,685 |
| opportunity_product__c | 2,647 |
| poc__c | 923 |
| approval_condition__c | 5 |

### File / attachment counts

| Object | Record Count |
|--------|-------------:|
| ContentDocument | 11,602 |
| ContentDocumentLink | 23,149 |
| ContentVersion | 11,726 |

Attachment payload size:

- `ContentVersion.ContentSize` total = `5,731,041,754 bytes`
- approximately `5.34 GiB`

Database size estimate:

- `information_schema.tables` total = `3,083,561,893 bytes`
- approximately `2.87 GiB`

Important note:

- the measured database size does not include all externalized file storage semantics in the same way as the `ContentVersion.ContentSize` aggregate
- for sizing, treat attachment payload as an additional storage driver beyond the logical row-store footprint

---

## Largest Tables In The Current Staging Dataset

These are the largest measured tables by `data_length + index_length`.

| Table | Rows | Total Size (MB) | Notes |
|------|-----:|----------------:|------|
| interface_log__c | 4,467,274 | 826.24 | Large internal/integration log table, not a default migration priority |
| lead | 370,756 | 686.05 | Largest core business object in baseline scope |
| leadhistory | 2,233,002 | 196.28 | History/audit-like workload |
| campaignmember | 672,261 | 161.48 | Large marketing relation table |
| _System_AuditLog | 495,998 | 150.16 | System audit table, not a default business migration priority |
| leadshare | 1,628,246 | 145.96 | Sharing/access-related derived/security surface |
| FieldPermissions | 414,512 | 123.52 | Access-definition data; not recommended as ordinary bulk business load |
| task | 253,581 | 108.36 | Large activity table |
| integration_log__c | 336,840 | 79.41 | Internal/integration log table |
| taskrelation | 560,976 | 54.05 | Activity relation table |
| org__c | 132,201 | 48.08 | Largest in-scope L2 business object |
| taskwhorelation | 522,662 | 46.35 | Activity relation table |
| emailmessage | 70,611 | 45.66 | Messaging-related table |
| FlowInterview | 182,226 | 41.59 | Runtime/automation state table |
| feeditem | 125,066 | 35.52 | Feed/social-style table |
| contentversion | 11,726 | 8.76 | Row-store table only; attachment payload is much larger separately |

### Practical sizing takeaway

For the currently proposed migration scope, the main business-volume drivers are:

- `lead`
- `campaignmember`
- `task`
- `org__c`
- `contentversion` attachment payload

The largest physical tables in staging also include logs, history, sharing, and runtime-state surfaces. Those tables matter if the scope later expands toward near-full-environment replication, but they should not automatically drive the first baseline-build sizing decision.

---

## Sizing Principles

1. The current workflow is pre-production baseline build, not a production cutover service.
2. The export side is likely to be constrained by Salesforce Bulk API throughput before EC2 CPU becomes the first bottleneck.
3. TiDB Cloud Essential uses provisioned capacity bounds (`min RCU` and `max RCU`) instead of dedicated node topology. You must size for:
   - baseline build throughput
   - steady validation traffic
   - short-lived branch creation and branch testing
4. The largest uncertainty is future attachment growth and future scope expansion into history/log/share tables.

---

## TiDB Cloud Essential Constraints That Matter Here

These current TiDB Cloud docs constraints materially affect this design:

1. TiDB Cloud Essential requires you to specify both a minimum and maximum number of RCUs, and it auto-scales within that range.
2. TiDB Cloud Starter and TiDB Cloud Essential do not support manual node-style sizing in the same way as Dedicated.
3. Branching is currently available for Starter and Essential, not for Dedicated.
4. Branches are currently beta, intended for short-term feature development and functional testing, and are not suitable for performance testing.
5. You cannot create branches for a TiDB Cloud Starter or Essential instance that is throttled or larger than `100 GiB`.
6. For TiDB Cloud Starter and TiDB Cloud Essential, `LOAD DATA INFILE` from S3 is not supported; only `LOAD DATA LOCAL INFILE` is supported. This fits the current design because the loader is expected to run on EC2 and push data into TiDB, rather than having TiDB pull directly from S3.

References:

- TiDB Cloud Essential creation and RCU bounds
- TiDB Cloud Branching beta overview
- TiDB Cloud limited SQL features

---

## Pricing Basis

All cost estimates below use the same region family as the current staging environment:

- AWS EC2 and EBS: `US East (N. Virginia)` / `us-east-1`
- TiDB Cloud Essential: `AWS N. Virginia (us-east-1)`

Pricing inputs used:

- `m7i-flex.2xlarge` Linux on-demand: `$0.38304 / hour`
- `m7i-flex.4xlarge` Linux on-demand: `$0.76608 / hour`
- `gp3` storage: `$0.08 / GB-month`
- `S3 Standard` storage in `us-east-1`: `$0.023 / GB-month`
- `S3 Standard` PUT/COPY/POST/LIST requests: `$0.005 / 1,000 requests`
- `S3 Standard` GET requests: `$0.0004 / 1,000 requests`
- TiDB Cloud Essential RCU price in `AWS N. Virginia (us-east-1)`: `$0.20 / RCU-month`
- TiDB Cloud Essential row-based storage price: `$0.20 / GiB-month`

Hourly conversion notes:

- monthly-to-hourly conversion below uses `730 hours / month`
- `gp3 300 GiB` = `$24 / month` = about `$0.0329 / hour`
- `gp3 500 GiB` = `$40 / month` = about `$0.0548 / hour`
- `2,000 RCU` baseline = `$400 / month` = about `$0.548 / hour`
- `4,000 RCU` baseline = `$800 / month` = about `$1.096 / hour`
- `10,000 RCU` ceiling = `$2,000 / month` = about `$2.740 / hour`
- `20,000 RCU` ceiling = `$4,000 / month` = about `$5.479 / hour`

Storage cost is small compared with RCU cost at the current measured dataset size:

- current measured row-store footprint `~2.87 GiB` = about `$0.57 / month` = about `$0.0008 / hour`
- even `100 GiB` row-based storage is only about `$20 / month` = about `$0.0274 / hour`
- current measured attachment payload `~5.34 GiB` on S3 Standard would be about `$0.12 / month` = about `$0.00017 / hour`

So the practical TiDB Cloud Essential cost driver is RCU, not storage, for the current migration scope.

---

## Option A: Cost-Sensitive Baseline

Use this when:

- budget pressure is high
- the immediate goal is to prove the baseline-build workflow
- the object whitelist stays close to the currently discussed business scope
- large log/history/share tables are not part of the first migration wave

### EC2 loader host

| Item | Recommendation |
|------|----------------|
| Instance | `m7i-flex.2xlarge` |
| vCPU | 8 |
| Memory | 32 GiB |
| Disk | `gp3` 300-500 GiB |
| Placement | Same AWS region as S3 + TiDB Cloud |

Why this is sufficient:

- current core business rows are moderate in size
- attachment payload is only ~5.34 GiB in the measured staging set
- this host mainly orchestrates export, staging, light transformation, and controlled loading

Estimated EC2 cost:

- with `300 GiB gp3`: about `$0.416 / hour`
- with `500 GiB gp3`: about `$0.438 / hour`

### TiDB Cloud

| Component | Recommendation |
|-----------|----------------|
| Plan | Essential |
| Minimum capacity | `2,000 RCU` |
| Maximum capacity | `10,000 RCU` |
| Storage target | keep the baseline comfortably below the `100 GiB` branching threshold |
| Branch usage | baseline + a small number of short-lived test branches |

Why this is sufficient:

- current measured business scope is small enough that storage headroom, not raw row count, is the first gating question
- keeps Essential spending bounded while still allowing auto-scaling within a practical range
- preserves the option to use TiDB Cloud branches for validation without paying for a larger dedicated topology too early

Estimated TiDB Cloud Essential cost:

- baseline floor at `2,000 RCU`: about `$0.548 / hour`
- if usage reaches the configured `10,000 RCU` ceiling: about `$2.740 / hour`
- row-based storage at the current measured staging size adds only about `$0.0008 / hour`

Estimated total hourly cost for Option A:

- normal baseline floor:
  - EC2 with `300 GiB gp3` + Essential `2,000 RCU` floor = about `$0.964 / hour`
  - EC2 with `500 GiB gp3` + Essential `2,000 RCU` floor = about `$0.987 / hour`
- high-burst ceiling:
  - EC2 with `300 GiB gp3` + Essential `10,000 RCU` ceiling = about `$3.156 / hour`
  - EC2 with `500 GiB gp3` + Essential `10,000 RCU` ceiling = about `$3.179 / hour`

### Risks of this cheaper option

- less headroom if many additional objects are added quickly
- less tolerance for large branch concurrency
- higher chance of throttling if baseline build and concurrent branch testing overlap too aggressively
- may require increasing `max RCU` if the controlled loader saturates the current ceiling

---

## Option B: Safer Headroom

Use this when:

- the staging dataset is already treated as close to real online scale
- multiple teams may test in parallel from the baseline
- more objects may be added soon after the first baseline build
- attachment growth is expected
- avoiding near-term resize churn is worth extra cost

### EC2 loader host

| Item | Recommendation |
|------|----------------|
| Instance | `m7i-flex.4xlarge` |
| vCPU | 16 |
| Memory | 64 GiB |
| Disk | `gp3` 500 GiB |
| Placement | Same AWS region as S3 + TiDB Cloud |

Why to choose it:

- more room for parallel object export/load
- more room for transformation, remap, and verification tasks
- lower operational risk if the loader implementation becomes heavier than initially planned

Estimated EC2 cost:

- with `500 GiB gp3`: about `$0.821 / hour`

### TiDB Cloud

| Component | Recommendation |
|-----------|----------------|
| Plan | Essential |
| Minimum capacity | `4,000 RCU` |
| Maximum capacity | `20,000 RCU` |
| Storage target | keep the baseline well below the `100 GiB` branching threshold |
| Branch usage | baseline + more frequent branch creation and heavier validation bursts |

Why to choose it:

- safer if the baseline becomes a long-lived shared validation substrate
- safer if branch count or rebuild frequency grows
- gives Essential more burst room before it hits the configured ceiling
- safer if migration scope expands toward a more complete environment mirror while still staying inside Essential's practical limits

Estimated TiDB Cloud Essential cost:

- baseline floor at `4,000 RCU`: about `$1.096 / hour`
- if usage reaches the configured `20,000 RCU` ceiling: about `$5.479 / hour`
- row-based storage at the current measured staging size adds only about `$0.0008 / hour`

Estimated total hourly cost for Option B:

- normal baseline floor:
  - EC2 with `500 GiB gp3` + Essential `4,000 RCU` floor = about `$1.917 / hour`
- high-burst ceiling:
  - EC2 with `500 GiB gp3` + Essential `20,000 RCU` ceiling = about `$6.300 / hour`

---

## Side-By-Side Comparison

| Area | Option A: Cost-Sensitive | Option B: Safer Headroom |
|------|--------------------------|--------------------------|
| Goal | Prove baseline workflow cheaply | Reduce resize risk and absorb faster growth |
| EC2 | `m7i-flex.2xlarge` | `m7i-flex.4xlarge` |
| EC2 CPU / RAM | `8 vCPU / 32 GiB` | `16 vCPU / 64 GiB` |
| EC2 Disk | `gp3 300-500 GiB` | `gp3 500 GiB` |
| TiDB Cloud plan | Essential | Essential |
| Essential min RCU | `2,000` | `4,000` |
| Essential max RCU | `10,000` | `20,000` |
| EC2 hourly cost | `$0.416-$0.438 / hour` | `$0.821 / hour` |
| TiDB baseline floor | `$0.548 / hour` | `$1.096 / hour` |
| TiDB burst ceiling | `$2.740 / hour` | `$5.479 / hour` |
| Total floor | `$0.964-$0.987 / hour` | `$1.917 / hour` |
| Total burst ceiling | `$3.156-$3.179 / hour` | `$6.300 / hour` |
| Branching fit | Small baseline + light branch use | More burst room for rebuild/test cycles |
| Best for | Tight budget, first baseline build | Near-online scale confidence, more branch headroom |
| Main tradeoff | Higher chance of future resize | Higher cost from day 1 |

---

## Reused EC2 Cost View

If an existing same-region sync/loader EC2 host is reused, do not count new EC2 instance cost again for this migration line item. In that case, the incremental infrastructure cost is primarily:

- TiDB Cloud Essential RCU
- TiDB Cloud row-based storage
- S3 Standard storage
- a very small amount of S3 request cost

This is the most realistic cost view if the team already owns a suitable Salesforce-to-TiDB sync host and only needs to add the new baseline-build workflow on top of it.

### S3 estimate for the current measured dataset

Assume:

- attachment/export payload stored in S3 Standard is approximately `5.34 GiB`
- request volume is low compared with storage and RCU cost

Estimated S3 cost:

- storage only: about `$0.123 / month`
- hourly equivalent: about `$0.00017 / hour`

For low daily traffic such as `100` or `500` accesses/day, S3 request cost remains negligible:

- `100` accesses/day:
  - GET request cost is effectively near zero
  - PUT/LIST request cost is also effectively near zero unless the export/import workflow is writing very large numbers of small objects
- `500` accesses/day:
  - still negligible compared with TiDB Cloud Essential baseline RCU cost

### Incremental hourly cost with reused EC2

#### Option A with reused EC2

TiDB Cloud Essential + S3 only:

- TiDB Essential floor: about `$0.548 / hour`
- TiDB row-based storage: about `$0.0008 / hour`
- S3 storage: about `$0.00017 / hour`

Estimated total incremental cost:

- floor: about `$0.549 / hour`
- burst ceiling (10,000 RCU): about `$2.741 / hour`

#### Option B with reused EC2

TiDB Cloud Essential + S3 only:

- TiDB Essential floor: about `$1.096 / hour`
- TiDB row-based storage: about `$0.0008 / hour`
- S3 storage: about `$0.00017 / hour`

Estimated total incremental cost:

- floor: about `$1.097 / hour`
- burst ceiling (20,000 RCU): about `$5.480 / hour`

---

## Daily Access Cost Scenarios

Important:

- `100` or `500` accesses/day do **not** materially change Essential cost at this scale
- the cluster is still dominated by minimum provisioned RCU
- so these access scenarios are best understood as cost allocation views, not true marginal-cost differences

### Scenario 1: 100 accesses/day

#### Option A with reused EC2

- daily cost:
  - `24 * $0.549 ≈ $13.18 / day`
- monthly cost:
  - about `$400.7 / month`
- allocated cost per access:
  - `$13.18 / 100 ≈ $0.132 / access`

Cost split:

- TiDB Essential baseline RCU: approximately `$13.15 / day`
- TiDB row-based storage: approximately `$0.02 / day`
- S3 storage + S3 requests: effectively near zero at this scale

#### Option B with reused EC2

- daily cost:
  - `24 * $1.097 ≈ $26.33 / day`
- monthly cost:
  - about `$800.7 / month`
- allocated cost per access:
  - `$26.33 / 100 ≈ $0.263 / access`

Cost split:

- TiDB Essential baseline RCU: approximately `$26.30 / day`
- TiDB row-based storage: approximately `$0.02 / day`
- S3 storage + S3 requests: effectively near zero at this scale

### Scenario 2: 500 accesses/day

#### Option A with reused EC2

- daily cost:
  - still about `$13.18 / day`
- monthly cost:
  - about `$400.7 / month`
- allocated cost per access:
  - `$13.18 / 500 ≈ $0.026 / access`

Cost split:

- TiDB Essential baseline RCU remains the dominant cost driver
- storage and S3 still remain negligible

#### Option B with reused EC2

- daily cost:
  - still about `$26.33 / day`
- monthly cost:
  - about `$800.7 / month`
- allocated cost per access:
  - `$26.33 / 500 ≈ $0.053 / access`

Cost split:

- TiDB Essential baseline RCU remains the dominant cost driver
- storage and S3 still remain negligible

### Practical takeaway

At `100` and `500` accesses/day, the question is not "how much does traffic cost?" The real question is "which minimum RCU floor are we willing to pay for always-on branchable baseline capacity?"

For a cost-sensitive start:

- Option A + reused EC2 is the more reasonable default
- Option B only makes sense if the team expects more frequent branch usage, more rebuilds, or stronger headroom requirements very soon

---

## Recommendation

Recommended default starting point:

- choose **Option A: Cost-Sensitive Baseline**

Reason:

- current measured business data volume does not justify an aggressively large EC2 host
- the current migration scope is still narrower than a full environment mirror
- the biggest cost-risk is overprovisioning before the first real baseline build proves the actual loader behavior
- TiDB Cloud Essential aligns with the desired branch-based validation workflow better than Dedicated, because branch support is currently on Starter and Essential rather than Dedicated

Upgrade to Option B only if one or more of these conditions appear:

- attachment volume grows materially beyond the current staging measurement
- migration scope expands to include more large history/log/share surfaces
- multiple test branches need to remain active concurrently for long periods
- baseline rebuild / verify / smoke steps show clear cluster pressure
- the loader implementation becomes materially more CPU/memory intensive than expected

If any of the following happens, revisit the plan choice itself, not just the RCU numbers:

- the baseline approaches the `100 GiB` branching threshold
- branch count requirements exceed current beta quotas
- performance testing becomes a formal requirement
- you need S3-side native import features instead of EC2-pushed loading

---

## Related Documents

- SALESFORCE_DATA_MIGRATION.md — migration workflow and baseline strategy
- SCHEMA_COMPATIBILITY.md — target schema and pack checks
- FIELD_MAPPING.md — record-data mapping contract
- BUSINESS_VALIDATION_CHECKLIST.md — baseline publish acceptance
- ROLLBACK_PLAN.md — branch reset / baseline rebuild recovery
