How do you test data quality on a production SQL Server database without slowing it down?

Move the heavy work off the primary and out of business hours: point data profiling and tests at a readable secondary or a replicated copy, schedule them in the overnight window, sample large tables, start with one or two threads, and use a read-only login. DataOps TestGen supports each of these and only ever runs SELECT.

Key points

  • In a DataKitchen case study published August 2026, data profiling five tables of under a million rows each against a live transactional Azure SQL database slowed the application for 20 minutes, so the team moved data profiling to a replicated copy on an overnight schedule.
  • On SQL Server Always On, adding ApplicationIntent=ReadOnly to the connection string routes queries to a readable secondary only when the connection targets the availability group listener and read-only routing is configured.
  • DataOps TestGen's sample-based data profiling uses database-native sampling on SQL Server, Azure SQL, and Synapse, and applies the sample to pattern and character analysis; record counts, distinct values, minimums, and maximums still cover the whole table.
  • TestGen schedules data profiling, test runs, and monitors in a chosen time zone, can pause a long data profiling run to stop its queries, and has a Max Threads setting for how many queries it sends at once.
  • TestGen runs only SELECT statements through a SQL login that needs SELECT on the target tables, and never runs INSERT, UPDATE, DELETE, CREATE, ALTER, or DROP.

Production SQL Server has a day job. The queries that test its data compete with the application for CPU, memory, IO, and locks, and the first full data profiling run is the heaviest thing you’ll send it.

DataKitchen has watched this go wrong. In a case study published in August 2026, a team pointed TestGen at a live transactional database and profiled five tables of under a million rows each. The application slowed down for 20 minutes. Data profiling moved to a replicated copy, on an overnight schedule.

Five ways to keep testing off the critical path

PracticeWhat it buys youHow to do it
Test a replica, not the primaryThe application never sees the loadAn Always On readable secondary, a log-shipped or restored copy, or a reporting warehouse
Run off-peakHeavy queries land when users are goneSchedule data profiling and tests in the overnight window
Sample large tablesLess to read on the biggest tablesSample-based data profiling for pattern and character analysis
Start with few threadsFewer queries at onceOne or two threads, raised once runs are stable
Read-only loginNothing can write, by constructionA SQL login with SELECT on the tables you test

Test a readable secondary or a copy

On an Always On availability group, add ApplicationIntent=ReadOnly to the connection string. A DataKitchen case study on a 1.2 TB SQL Server database found the two prerequisites that trip people up: the connection has to target the availability group listener, not an instance name, and read-only routing has to be configured on the group. Miss either and you’re on the primary, without an error.

No availability group? A nightly restored copy or the reporting warehouse works too. You test yesterday’s data, which is usually what the reports read anyway.

Schedule into the quiet window

TestGen schedules data profiling, test runs, and monitors. You pick a time zone and a frequency, or a cron expression for anything unusual, and the dialog shows the next run times before you save. If a long data profiling run is still going when users arrive, pause it to stop its queries and resume later. Stagger the long-running test suites rather than starting them together.

Sample the big tables

TestGen’s sample-based data profiling uses database-native sampling on SQL Server, Azure SQL, and Synapse, per its 2025 release notes. You set a sample percent and a minimum sample size per table group. The sample applies to pattern and character analysis. Record counts, distinct values, minimums, and maximums still cover the whole table.

For very large tables, the case study’s answer was views over a recent date range or one category at a time. If the table is partitioned, write the view so the partition filter still applies, or you’ve rebuilt the full scan you were avoiding.

Throttle concurrency

TestGen’s connection settings include Max Threads, the number of queries it runs at once, under Advanced Tuning. The case study started at one or two and raised it once runs were stable. That’s TestGen’s setting, not SQL Server’s max degree of parallelism. A DBA can also put the TestGen login in a Resource Governor workload group to cap its CPU and IO, as the same team did.

Keep the login read-only

TestGen needs a SQL login with SELECT on the tables you test. It reads information_schema.columns, sys.objects, and sys.partitions, which database users can read by default. It never runs INSERT, UPDATE, DELETE, CREATE, ALTER, or DROP, and it stores only computed results in its own database on a server you host.

Data profiling once, tests and monitors often

The first data profiling run reads every column, so it’s the one to put on a copy at night. Generated tests check the columns and rules you keep, so they can follow each load. Monitors ask less of each table: freshness compares a fingerprint of key columns, and volume records a row count. TestGen’s monitor docs suggest running them at roughly twice the rate your data changes.

So a common split: data profiling weekly or after big schema changes, tests after each load, and monitors every few hours.

Open-source TestGen is free for one user, one connection, and one project. Start at the SQL Server install page.

Frequently asked questions

Short answers to the follow-up questions people ask next.

Will data profiling a large SQL Server table lock it?

Data profiling reads; it doesn't write. Under SQL Server's default read committed isolation, a long SELECT takes shared locks as it reads, which can make writers wait on a busy table. That's the reason to run data profiling on a readable secondary or a copy, and to schedule it outside the hours the application is busy.

Can I point TestGen at an Always On readable secondary?

Yes. A DataKitchen case study on a 1.2 TB SQL Server database adds ApplicationIntent=ReadOnly to the connection string. It only routes to the secondary when the connection targets the availability group listener and read-only routing is configured; point it at an instance name and you quietly get the primary.

Does sampling make data profiling less accurate?

Only for some measures. In TestGen, sampling applies to pattern and character analysis, while record counts, distinct values, minimums, and maximums still cover the whole table. For exact pattern, character, and frequent-value counts, run data profiling without sampling, ideally on a copy.

Do monitors add load to production?

Some, because each monitor run queries the table. TestGen's monitor docs suggest running monitors at roughly twice the rate your data changes, not continuously. A table loaded nightly needs a monitor every 12 hours, not every five minutes.

Try it on your own data

DataOps TestGen is free and open source. Profile a table and generate its tests this afternoon.