MSSQL
For instructions on how to apply database migrations, please refer to the Getting Started documentation.
SQL database project
We use a SDK-style SQL project (sqlproj
) to develop the database locally. This means
we have an up-to-date representation of the database in src/Sql
, and any modifications needs to be
represented there as well. SDK-style SQL projects are still in preview the tooling is not yet
available in Visual Studio. However it is available in Visual Studio Code and Azure Data
Studio with the SQL Database Projects extension, which provides schema comparison
and more. You may also modify the .sql
files directly with any text editor.
To make a database change, start by modifying the .sql
files in src/Sql/dbo
. These changes will
also need to be applied in a migration script. Migration scripts are located in
util/Migrator/DbScripts
.
You can either generate the migration scripts automatically using the Schema Comparison functionality or by manually writing them. Do note that the automatic method will only take you so far and it will need to be manually edited to adhere to the code styles.
For added safe guards we have automated linting and validation to ensure the SQL project is always up to date with the migrations.
Modifying the database
Since we follow Evolutionary Database Design (EDD), any migration that modifies existing columns most likely needs to be split into at least two parts: a backwards compatible transition phase, and a non-backwards compatible phase.
Best practices
When writing a migration script there are a couple of best practices we follow. Please check the T-SQL Code Style for more details. But the most important aspect is ensuring the script can be re-run on the database multiple times without producing any errors or data loss.
Backwards compatible
Since we follow EDD the first migration needs to retain backwards compatibility with existing production code.
- Modify the source
.sql
files insrc/Sql/dbo
. - Write a migration script, and place it in
util/Migrator/DbScripts
. Each script must be prefixed with the current date.
Please take care to ensure any existing Stored Procedure accepts the same input parameters which ensures backwards compatibility. In the case a column is renamed, moved care needs to be taken to ensure the existing sprocs first checks the new location before falling back to the old location. We also need to ensure we continue updating the old data columns, since in case a rollback is necessary no data should be lost.
Data migration
We now need to write a script that migrates any data from the old location to the new locations.
This script should ideally be written in a way that supports batching, i.e. execute for X number of
rows at a time. This helps avoiding locking the database. When running the scripts against the
server please keep running it until it affects 0 rows
.
Non-backwards compatible
These changes should be written from the perspective of "all data has been migrated". And any old Stored Procedures that were kept around for backwards compatibility should be removed. Any logic for syncing old and new data should also be removed in this step.
Since Sql/dbo
represents the current state we need to introduce a "future" state which we will
call dbo_finalization
.
- Copy the relevant
.sql
files fromsrc/Sql/dbo
tosrc/Sql/dbo_finalization
. - Remove the backwards compatibility which is no longer needed.
- Write a new Migration and place it in
src/Migrator/DbScripts_finalization
, name itYYYY-0M-FinalizationMigration.sql
.- Typically migrations are designed to be run in sequence. However since the migrations in DbScripts_future can be run out of order, care must be taken to ensure they remain compatible with the changes to DbScripts. In order to achieve this we only keep a single migration, which executes all backwards incompatible schema changes.
[Not Yet Implemented] Manual MSSQL migrations
There may be a need for a migration to be run outside of our normal update process. These types of migrations should be saved for very exceptional purposes. One such reason could be an Index rebuild.
- Write a new Migration with a prefixed current date and place it in
src/Migrator/DbScripts_manual
- After it has been run against our Cloud environments and we are satisfied with the outcome,
create a PR to move it to
DbScripts
. This will enable it to be run by our Migrator processes in self-host and clean installs of both cloud and self-host environments