Database Design and Migration
PostgreSQL, MySQL, and MongoDB schema design, indexing, query tuning, backups, and data migrations that move between engines with validated cutover.
See our work:

Most databases are not designed. They accumulate. A first table for customers, another for orders, an index added during an incident and never removed, dates stored as text beside timestamps. The application keeps working, queries get slower, and the team learns to wait.
The other half of this service is movement: a business outgrows the MySQL instance that came with its hosting, or a hosted Postgres has to move closer to users. Those jobs tend to fail in the hours after the rows land, when nobody can say whether all of them arrived and whether they still mean the same thing.
What this work covers
Schema design starts from the questions the system has to answer. We work out the entities, the relationships, which values must be unique, and where a constraint belongs in the database rather than in application code. Some columns get denormalised on purpose, when read speed is worth the duplication.
Indexing solves most performance problems. We read the query patterns, the slow query log, and the execution plans, then build composite indexes in the order filters are used, add partial indexes for the rows that matter, and drop indexes that only slow writes.
Query tuning covers the shape of the requests. N+1 loops from ORMs become a single join, pagination moves away from large offsets, and heavy reporting runs against a replica instead of the transactional tables. Pooling and statement timeouts are set for the real workload.
Backups are designed with recovery in mind. Automated snapshots cover the coarse case, write-ahead log or binlog archiving gives point-in-time recovery to a chosen moment, and the restore procedure is rehearsed on a copy.
Migrations cover schema changes on a live database and full moves between engines or hosts. Depending on the source we use logical replication, dump and restore, or change data capture, with a backfill stage where the application cannot be stopped.
Validation compares the two sides: row counts, checksums, totals on money columns, uniqueness, foreign keys, and a field-level sample. Access control gives each application and person the minimum rights it needs, keeps migration credentials apart from runtime credentials, requires TLS, and logs production access.
Who this is for
Teams whose product outgrew the model that shipped with version one. Queries that ran in milliseconds take seconds, reports read the live tables at the busiest hour, and nobody remembers which column is authoritative.
Companies planning a move: an engine change for cost or features, a consolidation into one managed service, or a relocation for latency and data residency.
Teams that inherited a system with no migrations folder, no backup policy, and no test data, where the current state has to be described first.
Businesses facing an audit, where the questions are who can read the customer table and whether a deleted record can be recovered.
What we deliver
- A data model document with entities, relationships, constraints, and the decisions that had to be argued about
- Migration files versioned in your repository, so schema changes reproduce in staging and production
- An indexing plan and the tuning changes as application code, with before and after execution plans recorded
- A runbook covering backup schedule, retention, restore steps, and the time a real restore took
- A cutover plan with a timestamp per step, the freeze duration, and the rollback trigger
How an engagement runs
Inventory and baselining takes three to five days on a normal system. We read the schema, list queries by frequency and cost, measure size and growth, and check the backups. On a migration we also list every client of the database, including cron jobs and spreadsheets nobody classified.
Design produces the target schema, the index changes, and the code changes, each with a reason. A migration also gets the engine choice and the mapping from source tables or collections to target tables.
Then we rehearse on a copy, with production data restored into a staging instance, so the timing we quote is measured. Application-level problems show up here: implicit type casting, dates stored as local strings, and reports that return different numbers when a join changes shape.
Cutover follows your traffic pattern. The old database stays authoritative until the new one has caught up, writes pause for the shortest period the source allows, the application is pointed at the target, and reconciliation runs at once.
If reconciliation fails
Rollback is driven by the reconciliation report. If row counts, checksums, or money-column totals disagree beyond the tolerance agreed in advance, we stop, keep the old database authoritative, and point the application back to it, which on a managed setup is a connection string change and a redeploy rather than a restore from backup. Writes were frozen only during the switch, so the only data at risk is the window captured in the change log, and those writes are replayed into the target before a second attempt. If the mismatch turns out to be a modelling error, the old instance stays in service while the mapping is corrected and the rehearsal repeated, so you get a new cutover date instead of an improvised one. Rolling back days later is a different operation, which is why the old snapshot and the change log are kept until you agree the new database has settled.
What it costs
Database work runs at our flat rate of $39 per hour, or as a fixed scope once the inventory has shown how many tables, how much data, and how many application queries are involved. Hourly suits ambiguous jobs such as a system with no documentation. Fixed scope suits a migration whose source and target are both known, because the rehearsal gives us a defensible number.
Scope drivers are the size of the dataset, how complex the queries that touch it are, whether the move changes engine or only host, how much downtime the business accepts, and whether history has to be reconciled for an audit. A schema review and index clean-up on one database is typically days. A cross-engine migration with application changes runs in weeks, quoted in phases so you can stop after the rehearsal.
The pricing page sets out the hourly rate, the monthly capacity plans from $2,699, and the published typical-order budgets.
Proof
The Big Mail Project is a postcard sending platform built on Laravel, Node.js, React, and Next.js, with both MongoDB and MySQL in its documented stack. That pairing is the everyday version of this service: transactional records in the relational store, flexible document data in MongoDB, and code that stays explicit about which store answers what.
Nubisreservation is a booking platform for restaurants, hotels, and service providers, built with Laravel and MySQL with Stripe handling payments, and used through a web application plus iOS and Android apps. It shows what a schema has to support when one dataset serves several clients: availability lookups that stay fast under load, reservations that cannot collide, and payment rows that reconcile against the provider.
KOKO-MIX Admin is the internal platform we built for a ready-mix concrete supplier, combining an Android app for drivers, an admin panel, and real-time chat on Firebase. The delivered scope was a shared operational dataset across field devices and the office, with job details moving between roles. That is the access control side of this service in practice: who may see which delivery, and which device may write. Vasilkoff no longer presents that product as a live service, so claims stay within the recorded scope.
Related services
- Web development for the application work around the data model
- API development and integration when outside systems read or write your data
- CMS migration when a platform move pulls a content database along with it
- Mobile backend and cloud infrastructure for managed databases and environments
- Custom web application development when the data model is designed as part of a new product
Next step
Send us the engine you run, roughly how large the database is, and the outcome you want. For performance work that means the queries that hurt and when they hurt. For a move it means the source, the intended target, and the downtime your business can tolerate.
Contact us with those details, or put the scope through the Vasilkoff.info estimator to get a cost range first.