MysqlToMsSql: Tools and Best Practices for Smooth Database Conversion

Migrating from MySQL to MSSQL: A Step-by-Step Guide for DevelopersMigrating a production database from MySQL to Microsoft SQL Server (MSSQL) is a multi-step project that touches schema design, data types, SQL dialects, stored code, performance tuning, and application compatibility. This guide walks through planning, preparation, migration, validation, and post-migration optimization with concrete steps, examples, and practical tips to reduce downtime and risk.


1. When and why to migrate

Common reasons to move from MySQL to MSSQL:

  • Corporate standardization — company policy or existing Microsoft ecosystem adoption.
  • Feature requirements — need for advanced features such as SQL Server Integration Services (SSIS), Query Store, Transparent Data Encryption (TDE), or richer analytics with SQL Server Reporting Services (SSRS) / Analysis Services.
  • Performance and scale — in some workloads MSSQL can offer better concurrency controls or enterprise features.
  • Tooling and support — preference for Microsoft tooling (SSMS, Azure integration) and enterprise support.

Assess whether migration is necessary: migrating costs time and money; if requirements can be met by MySQL or managed MySQL (AWS RDS, Azure Database for MySQL), staying put may be preferable.


2. High-level migration plan

  1. Inventory current system: schema, data size, stored procedures/triggers, scheduled jobs, users/roles, application queries.
  2. Map feature gaps and differences: data types, SQL dialect, functions, transactions, isolation levels.
  3. Choose migration strategy: big-bang (downtime) vs. phased (replication/dual-write).
  4. Prepare target MSSQL environment: sizing, collation, authentication mode, network/security.
  5. Convert schema and code; migrate data; translate stored procedures and triggers.
  6. Test thoroughly (unit, integration, performance, regression).
  7. Cutover and monitor; rollback plan ready.
  8. Post-migration tuning and cleanup.

3. Key differences to consider

  • Authentication: MySQL offers user accounts per server; MSSQL supports Windows and SQL authentication, Active Directory integration.
  • Collation and case sensitivity: MySQL default collation may differ. MSSQL collation is set at server/database/column level — ensure consistent behavior.
  • Data types: mapping is not always 1:1 (detailed mappings below).
  • Auto-increment vs. IDENTITY: MySQL’s AUTO_INCREMENT → MSSQL IDENTITY.
  • SQL dialect: LIMIT vs. TOP/OFFSET-FETCH, GROUP_CONCAT vs. STRING_AGG (SQL Server 2017+), different date functions.
  • Stored code: MySQL uses different procedural language (stored procedures, triggers) — conversion often manual.
  • Transactions and isolation: default isolation levels and behaviors differ — MSSQL default is READ COMMITTED.
  • Indexing and optimizer hints: syntax and behavior differ; queries may need rewriting or different indexes.

4. Schema and datatype mapping (common mappings)

MySQL type MSSQL equivalent Notes
INT, TINYINT, SMALLINT, MEDIUMINT, BIGINT INT, TINYINT, SMALLINT, INT (no MEDIUMINT), BIGINT MEDIUMINT (MySQL) map to INT and check range
VARCHAR(n) VARCHAR(n) MSSQL max 8000; use VARCHAR(MAX) for larger
TEXT, TINYTEXT, MEDIUMTEXT, LONGTEXT VARCHAR(MAX) or NVARCHAR(MAX) Use NVARCHAR(MAX) if Unicode needed
CHAR(n) CHAR(n)
DATETIME, TIMESTAMP DATETIME2 / DATETIME DATETIME2 has higher precision; consider datetimeoffset for zones
DATE DATE
TIME TIME
BLOB, LONGBLOB VARBINARY(MAX)
ENUM CHECK constraint or lookup table Better to use small reference table for portability
SET bitmasking or separate table Complex to emulate; consider normalized design
BOOLEAN, BOOL BIT MySQL BOOLEAN is alias for TINYINT(1)
FLOAT, DOUBLE, DECIMAL FLOAT, FLOAT, DECIMAL(precision,scale) Match precision carefully

5. Tools and approaches

Options for migration:

  • SQL Server Migration Assistant (SSMA) for MySQL — Microsoft tool that converts schema, data, and some procedural code. Good first pass but manual adjustments are common.
  • Import/Export via CSV or BCP/BULK INSERT — simple but loses stored procedures/triggers and may require careful handling of encodings and identity values.
  • Linked servers and OPENQUERY — useful for one-off queries across DBs during migration.
  • Replication / CDC solutions — use change data capture to keep systems in sync for phased cutover (e.g., Debezium → Kafka → SQL Server, or custom ETL).
  • Third-party ETL tools — Pentaho, Talend, AWS DMS, Azure Database Migration Service (DMS).
  • Custom scripts (Python, Go, Node) — useful when transformations are complex.

Recommended starting point: run SSMA to convert schema and identify manual changes, use SSIS or DMS for data movement, and set up CDC/replication if minimal downtime is required.


6. Detailed step-by-step migration

Step A — Inventory and discovery

  • List all databases, tables, row counts, and growth rates.
  • Export schema DDL from MySQL.
  • Extract list of views, stored procedures, functions, triggers, events.
  • Capture user privileges, jobs, and external dependencies (cron jobs, application schedules).

Step B — Prepare target MSSQL

  • Choose appropriate SQL Server edition (Express, Standard, Enterprise, Azure SQL).
  • Set server-level collation that matches expected string behavior.
  • Configure logins, users, roles, and permissions.
  • Plan disk layout: data files (.mdf/.ndf) vs. log files (.ldf), tempdb sizing.
  • Configure backups, maintenance plans, and high availability if needed.

Step C — Convert schema

  • Run SSMA for MySQL to generate a baseline conversion.
  • Manually review:
    • Data type mappings, lengths/precision.
    • Primary keys, unique constraints, indexes.
    • Auto-increment columns → IDENTITY; preserve current values by setting IDENTITY_INSERT ON during import if needed.
    • Default values and computed columns.
    • Collation on text columns.
  • Convert ENUM/SET to normalized tables or CHECK constraints.
  • Rewrite views and stored procedures:
    • Translate MySQL procedural constructs (IF, WHILE, LOOP) to T-SQL.
    • Replace MySQL-specific functions (e.g., CONCAT, DATE_FORMAT) with T-SQL equivalents (CONCAT, FORMAT, CONVERT).
    • For GROUP_CONCAT use STRING_AGG (SQL Server 2017+) or FOR XML PATH workaround.

Example: LIMIT 10 OFFSET 20 → OFFSET-FETCH

-- MySQL SELECT * FROM orders ORDER BY order_date DESC LIMIT 10 OFFSET 20; -- MSSQL SELECT * FROM orders ORDER BY order_date DESC OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY; 

Step D — Migrate data

  • For small-medium datasets: use SSMA or SSIS to bulk copy data.
  • For large datasets: use BCP or BULK INSERT with batch sizes to avoid long transactions.
  • Preserve NULLs and encoding (use UTF-8/Unicode mapping to NVARCHAR if your data contains non-ASCII).
  • Handle identity columns:
    • If preserving original IDs, enable IDENTITY_INSERT ON for the target table during import.
  • For referential integrity: load parent tables before child tables or disable constraints and re-enable/validate after load.
  • Examples:
    • BCP export/import
    • SSIS Data Flow with transformations for type differences

Step E — Migrate code and logic

  • Convert stored procedures, functions, triggers manually — test each procedure.
  • Replace MySQL session variables, user variables (@var) with T-SQL variables (DECLARE @var datatype).
  • Reimplement triggers to match firing semantics (AFTER/INSTEAD OF differences).
  • Replace user-defined functions carefully; scalar vs. inline table-valued functions have different performance profiles in MSSQL.

Step F — Testing

  • Schema validation: compare column counts, types, nullability, and constraints.
  • Data validation: row counts, checksums, sampling, and full hash comparisons for critical tables.
  • Functional testing: run application test-suite against MSSQL backend.
  • Performance testing: compare slow queries and execution plans; add indexes if needed.
  • Concurrency and load testing: simulate production workloads to find locking/contention issues.

Sample data validation query (row counts and checksum):

-- Row counts SELECT 'table_name' = 'users', COUNT(*) FROM users; -- Simple checksum example SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM users; 

Step G — Cutover strategies

  • Big-bang: stop writes on MySQL, final sync, point application to MSSQL. Simpler but requires downtime.
  • Dual-write: application writes to both DBs during transition (requires careful idempotency and reconciliation).
  • Replication/CDC: replicate changes from MySQL to MSSQL until cutover moment (more complex but minimal downtime).
  • Rolling cutover: migrate services one at a time to minimize risk.

Prepare a rollback plan and a tested timeline. Communicate downtime windows to stakeholders.


7. Performance tuning after migration

  • Review execution plans in SQL Server Management Studio (SSMS) and Query Store.
  • Update statistics and rebuild indexes after bulk loads:
    • UPDATE STATISTICS schema.table; or sp_updatestats
    • ALTER INDEX ALL ON table REBUILD
  • Consider clustered vs. nonclustered indexes carefully; primary key choice affects clustered index default.
  • Use filtered indexes, included columns, and indexed views when beneficial.
  • Tune tempdb and max degree of parallelism (MAXDOP) as needed.
  • Monitor waits (CXPACKET, LCK_M_X) to diagnose concurrency issues.

8. Security and maintenance

  • Configure encryption at rest (TDE) and in transit (TLS).
  • Migrate user accounts to Windows/AD authentication where possible.
  • Apply principle of least privilege for db roles.
  • Set up automated backups, log shipping, availability groups, or Azure failover groups for HA/DR.
  • Configure auditing via SQL Server Audit if required.

9. Common pitfalls and how to avoid them

  • Ignoring collation differences → unexpected string comparison behavior. Verify collations.
  • Assuming 1:1 data type compatibility → data truncation or precision loss. Review types.
  • Not converting stored procedures correctly → functional regressions. Manual testing is required.
  • Overlooking time zone handling for TIMESTAMP/DATETIME data → use datetimeoffset if needed.
  • Failing to test performance under load → surprises after cutover. Run realistic load tests.
  • Not planning identity preservation → referential integrity may break. Use IDENTITY_INSERT when needed.

10. Checklist before cutover

  • Schema converted and reviewed.
  • All critical data migrated and verified (row counts, checksums).
  • Stored procedures, triggers, and views converted and tested.
  • Application tested against MSSQL in staging (integration and load tests).
  • Backups and recovery tested on MSSQL.
  • Monitoring and alerting configured.
  • Rollback plan documented and rehearsed.

11. Appendix — Quick translation snippets

  • AUTO_INCREMENT → IDENTITY(1,1)

    CREATE TABLE users ( id INT IDENTITY(1,1) PRIMARY KEY, username VARCHAR(100) ); 
  • MySQL variable → T-SQL “`sql – MySQL SET @count = (SELECT COUNT(*) FROM orders);

– T-SQL DECLARE @count INT; SELECT @count = COUNT(*) FROM orders;


- GROUP_CONCAT → STRING_AGG (SQL Server 2017+) ```sql SELECT customer_id, STRING_AGG(product_name, ',') AS products FROM order_items GROUP BY customer_id; 
  • Replace IFNULL(expr1, expr2) with ISNULL(expr1, expr2) in T-SQL.

Migrating from MySQL to MSSQL is a complex but manageable process with careful planning, tool-assisted conversion, thorough testing, and staged execution. Use SSMA to accelerate conversion, supplement with SSIS/DMS for data movement, and allocate time for manual translation of business logic and performance tuning.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *