Encrypting everything sounds great until performance dies. This article explains the encryption levels available, their performance impact, and how to choose what to encrypt.
Available Levels
- None: Data stored as plaintext. Default for public/non-sensitive columns.
- Column-level: Specific columns are encrypted (e.g. email, phone, address). Other columns remain queryable. Search still works on the unencrypted columns.
- Record-level: Entire records are encrypted as a blob. Queries can only filter on a small set of indexed metadata columns; deep search is impossible without decryption.
- Field + integrity hash: Column-level plus an HMAC stored alongside, catching tampering.
What to Encrypt
- Always: Passwords (hashed, not encrypted), API tokens, payment-instrument tokens, social security/national ID numbers, health records.
- Often: Email addresses, phone numbers, postal addresses, date of birth.
- Sometimes: Names (consider tradeoff with search), free-text notes (consider redaction instead).
- Rarely: Public profile fields, system metadata.
Performance Tips
- Keep decryption caches enabled — a 60-second per-process cache massively reduces re-decryption cost.
- Prefer column-level over record-level whenever search/filtering is needed.
- Don't encrypt a column that's used in WHERE clauses unless you're prepared for full-table scans.
- Batch decryption when fetching lists — single round-trip to the engine for N values is faster than N round-trips.
Worked Examples
- Healthcare app: Patient name, DOB, address, all medical notes — column-encrypted. Patient ID stays plaintext for indexing.
- Marketplace: Buyer/seller messaging encrypted; product titles and descriptions plain to allow search.
- Finance app: Account numbers and routing details column-encrypted with integrity hash. Transaction amounts plain to allow reporting.
Tip: Run a load test before turning on column-level encryption on a hot table. The 2× latency increase per read can saturate your DB if the workload isn't expected.