Skip to main content

Data Access Interview Questions

Every question has a short model answer and a link to the lesson example that shows it in code. Levels: F = Fresher (0-2 yrs), M = Mid (3-5 yrs), S = Senior (6-9 yrs), A = Architect / Lead (10+ yrs).

ADO.NET

FWhat is ADO.NET, and what are its main classes for SQL Server?concept

ADO.NET is the low-level part of .NET for talking to databases. For SQL Server, the main classes come from Microsoft.Data.SqlClient: SqlConnection (the connection), SqlCommand (SQL text or a procedure name), SqlParameter (a value), SqlDataReader (rows, forward only), SqlTransaction, and SqlException. Dapper and EF Core are built on top of it.

FWhat is the difference between ExecuteScalar, ExecuteReader, and ExecuteNonQuery?concept

ExecuteScalar returns one value, the first column of the first row, such as a COUNT(*). ExecuteReader returns a reader over many rows. ExecuteNonQuery runs INSERT, UPDATE, or DELETE and returns the number of rows changed. Each has an Async version that should be preferred.

FWhat is SQL injection, and how do you prevent it in C#?concept

SQL injection is user input changing what a query does, because the input was joined into the SQL text. Typing x' OR '1'='1 into an unsafe student search returned all 10,012 students. Prevent it with parameters: the value travels separately from the SQL, so it is only ever a value.

MWhat is connection pooling, and how should code use connections because of it?concept

ADO.NET keeps a pool of open connections per connection string. Disposing a connection returns it to the pool, and the next open takes it back almost instantly: 100 opens took 3 ms after a first open of 472 ms. So open as late as possible, dispose as early as possible, and never keep a connection in a field.

MHow do you read a nullable column with a SqlDataReader?coding

A NULL column arrives as DBNull.Value, not null, and calling GetString or GetInt32 on it throws. Check reader.IsDBNull(ordinal) first, then read the value, for example Address = reader.IsDBNull(i) ? null : reader.GetString(i).

MHow do you call a stored procedure with an output parameter from ADO.NET?coding

Set CommandType = CommandType.StoredProcedure and use the procedure name as the command text. Add input parameters normally, and add the output parameter with Direction = ParameterDirection.Output and a size. After ExecuteNonQueryAsync, read its Value, as with @ReceiptNumber from usp_RecordFeePayment.

SWhy can AddWithValue slow a query down, and what do you use instead?concept

AddWithValue guesses the SQL type from the C# value, and a string becomes NVARCHAR. Against a VARCHAR column, SQL Server converts the column and can scan instead of seek: finding a student by admission number read 37 pages instead of 2. Use Parameters.Add with an explicit SqlDbType and size that match the column.

How to answer:

Explain the type guess, the implicit conversion on the column side, and its effect on index use. Give the fix, and mention that plan-cache bloat from varying string lengths is a second reason.

SA school portal becomes slow at 9 a.m., then fails with 'Timeout expired... obtaining a connection from the pool'. What do you check?scenario

The pool is exhausted: connections are being opened and not returned. Look for connections, readers, or commands that are not disposed, especially on exception paths, and for connections held during slow work. Fix with await using everywhere, short-lived connections, and async calls; only then consider raising Max Pool Size.

How to answer:

Name the cause (pool exhaustion), how to confirm it (counters or sp_who for sleeping connections from the app), the code fixes, and why raising the pool size first only hides the leak.

AWhen would you still choose plain ADO.NET over Dapper or EF Core in a new system?design

When you need full control or maximum throughput with no mapping layer: bulk loading with SqlBulkCopy, streaming huge result sets, table-valued parameters, or a small hot path measured as too slow. For ordinary CRUD, the hand-written mapping costs more in time and bugs than it saves, so most teams use EF Core or Dapper and drop to ADO.NET only where measured.

How to answer:

Show you know the trade-off: control and speed against code volume and mistakes. Give concrete cases, and say how you would keep such code isolated behind a repository.

Dapper

FWhat is Dapper, and how is it different from EF Core?concept

Dapper is a micro-ORM: you write the SQL, and it adds parameters and maps result rows to objects. EF Core is a full ORM: it also writes the SQL from LINQ, tracks changes to entities, and saves them. Dapper gives more control with less magic; EF Core gives more productivity for everyday CRUD.

FWhich Dapper methods would you use to get a list, a single row, and a count?coding

QueryAsync<T> for a list, QuerySingleOrDefaultAsync<T> for one row by a unique key (null if none, an exception if two), and ExecuteScalarAsync<int> for a count. ExecuteAsync runs INSERT, UPDATE, DELETE, or a procedure and returns the rows changed.

FHow do you pass parameters to a Dapper query, and is it safe from SQL injection?concept

Pass an object, often anonymous: new { LastName = lastName } fills @LastName. Dapper creates real parameters, so the values never become part of the SQL text and injection is not possible. Joining user input into the SQL string yourself is still unsafe.

MHow does Dapper match columns to properties, and what happens when a name does not match?concept

By name, ignoring case. A column with no matching property is ignored, and a property with no column keeps its default value; neither raises an error. That makes renamed columns or missing aliases a silent bug, so use explicit column lists with aliases and test each query.

MWhat is multi-mapping in Dapper, and what does splitOn do?coding

Multi-mapping reads one joined row into several objects, for example an Enrollment and its Student, and a function you supply connects them. splitOn names the column where each next object starts; it defaults to Id. For one-to-many results, a dictionary keeps one parent per key.

MHow do you read an output parameter from a stored procedure with Dapper?coding

Use DynamicParameters: add the inputs, and add the output with a type, a size, and direction: ParameterDirection.Output. Call ExecuteAsync with commandType: CommandType.StoredProcedure, then read it with Get<string>("@ReceiptNumber").

SYour Dapper search by admission number is slow, although the column has a unique index. What could be wrong?scenario

Dapper sends C# strings as NVARCHAR(4000). Against the VARCHAR column, SQL Server converts the column and may scan the index instead of seeking. Pass new DbString { Value = ..., IsAnsi = true, Length = 15 } so the parameter matches the column type, then confirm the seek in the plan.

How to answer:

Start from the symptom, explain the implicit conversion, show the DbString fix, and say how you would prove it: the execution plan or logical reads before and after.

SA dashboard makes six small queries per page load. How would you reduce the cost with Dapper?scenario

Send them together with QueryMultipleAsync and read each result in order from the grid reader: one round trip instead of six. Select only the columns the dashboard shows, mapped to DTOs or tuples. If it is still slow, look at the queries' plans and consider caching (Module 12).

How to answer:

Name round trips as the cost, show QueryMultiple, mention the order-dependent reading, and add what you would measure before and after.

AWould you use EF Core and Dapper in the same application? How would you organize it?design

Yes, commonly: EF Core for writes and ordinary reads of entities, where change tracking and LINQ save time, and Dapper for heavy reports and dashboards, where hand-tuned SQL matters. Both use the same connection string and can share a transaction. Keep each behind a repository or query interface so callers do not know which tool answers.

How to answer:

Give the split by workload, mention sharing connections and transactions, and explain how the abstraction keeps the choice reversible. A brief CQRS mention fits at this level.

EF Core basics

FWhat is EF Core, and what is a DbContext?concept

EF Core is Microsoft's ORM for .NET: you query with LINQ, and it writes the SQL, creates objects, tracks changes, and saves them. A DbContext is one session with the database; each DbSet<T> is a table you can query. A context should be short-lived, such as one per web request.

FWhat is the difference between database-first and code-first?concept

Database-first starts from an existing database: schema changes are made in SQL, and EF Core maps to the result, often helped by scaffolding. Code-first starts from C# classes, and EF Core migrations create and change the database. Database-first fits shared or older databases; code-first fits new apps that own their database.

FWhat does SaveChangesAsync do?concept

It looks at every tracked entity, finds the added, modified, and deleted ones, and sends the matching INSERT, UPDATE, and DELETE statements in one transaction. Changing one property of a loaded student produced an UPDATE of that single column.

MWhat does dotnet ef dbcontext scaffold generate, and why use --no-onconfiguring?concept

It reads a database and writes one class per table and view, plus a DbContext with the full mapping: lengths, types, keys, indexes, defaults, and relationships. Without --no-onconfiguring, it also puts the connection string in the generated code, which leaks credentials into source control.

MWhat is a value converter in EF Core? Give an example.coding

It translates a property value to a column value and back. In the SMS, Gender is an enum in C# and a CHAR(1) code in the database: HasConversion(g => ((char)g).ToString(), c => (Gender)c[0]). HasConversion<string>() stores an enum by name. Converters also apply to query parameters.

MWhy might EF Core throw 'The LINQ expression could not be translated', and how do you fix it?concept

The query calls something SQL cannot run, such as your own C# method (s.GetAgeOn(date)). EF Core throws instead of loading everything. Rewrite the condition with translatable parts, such as a date comparison, rather than calling ToList first and filtering in memory.

SHow do you map rich domain entities, with constructors and read-only properties, to an existing database with EF Core?design

Keep the entities in the core project and put all mapping in IEntityTypeConfiguration classes in the data project. EF Core can call a constructor whose parameter names match properties, map read-only properties that are configured explicitly, and use value converters for enums. The entities need no EF Core attributes or base classes.

How to answer:

Describe the layering first, then the specific features (constructor binding, explicit property mapping, backing fields, converters), and say how you verified the mapping, such as comparing against the scaffolded model.

SA colleague wants to scaffold the database again every time a column changes, overwriting the entity classes. What do you advise?scenario

Regenerating overwrites anything added by hand, such as rules, constructors, or enums, and makes the domain model follow the database. Keep scaffolded output as a reference only, map hand-written entities through configuration classes, and change one configuration line when a column changes.

How to answer:

Explain the risk with a concrete loss, propose the separation, and mention a check that catches mapping drift, such as an integration test or a column comparison script.

AWho should own schema changes in a database-first EF Core system, and how do you keep code and database in step?design

The database scripts are the source of truth, reviewed and versioned like code, and run in order by deployment. EF Core mappings follow them. Keep both in one repository, deploy the script before the code that needs it, prefer additive changes, and run integration tests against a database built from the scripts so drift fails the build.

How to answer:

Cover ownership, versioning, deployment order, backward-compatible changes, and automated drift detection. Compare briefly with code-first migrations.

EF Core relationships

FWhat is a navigation property in EF Core?concept

A property that points to a related entity instead of holding a value. A reference navigation points to one entity, such as Enrollment.Section; a collection navigation holds many, such as FeeInvoice.Payments. The foreign key, such as SectionId, is always loaded; navigations only when requested.

FWhat do Include and ThenInclude do?coding

Include loads a navigation of the entity being queried; ThenInclude continues from that navigation to the next level. Kabir's student, enrollments, sections, classes, and years came back in one query with Include(s => s.Enrollments).ThenInclude(e => e.Section).ThenInclude(...).

FWhat is the difference between eager, explicit, and lazy loading?concept

Eager loading fetches related data in the same query with Include. Explicit loading fetches it later, on request, with Entry(...).Collection(...).LoadAsync(). Lazy loading fetches it automatically the first time a navigation is read, through proxies, which hides queries and often causes N+1 problems.

MHow do you configure a one-to-many relationship with the Fluent API?coding

From either side, for example builder.HasMany(i => i.Payments).WithOne(p => p.FeeInvoice) .HasForeignKey(p => p.FeeInvoiceId). Use WithMany() with no argument when the other side has no collection. Configuring it explicitly is needed when names do not follow conventions, such as ClassId with a SchoolClass navigation.

MWhat is a global query filter, and when would you use one?concept

A condition EF Core adds to every query on an entity, configured with HasQueryFilter. It suits rules that must never be forgotten, such as hiding soft-deleted rows or, in multi-tenant systems, other tenants' rows. IgnoreQueryFilters switches it off; EF Core 10 can switch off one named filter.

MWhy might SaveChanges fail on a table with triggers, and how do you fix it?concept

EF Core reads generated values back with an OUTPUT clause, and SQL Server rejects OUTPUT without INTO on tables with enabled triggers. Declare each trigger with ToTable("Marks", t => t.HasTrigger("tr_Marks_Audit")), and EF Core switches to a method that works.

SA fee report shows full balances for invoices that are partly paid. The code calls invoice.Balance. What do you suspect?scenario

The invoices were loaded without their payments, so Payments is empty and AmountPaid is 0. Nothing throws. Add Include(i => i.Payments), or better for a report, project the sum of payments in SQL, and add a test with a partly paid invoice so the bug cannot return quietly.

How to answer:

Explain why missing related data is silent, give both fixes and when each fits, and finish with how you would prevent a regression.

SWould you enable lazy loading in a web API? Why or why not?design

Generally no. Every navigation access can issue a query, so loops become N+1 problems, the queries are invisible in the code, and serializing an entity can trigger loads across the whole graph. Load deliberately with Include or project to DTOs, which also keeps the API's shape independent of the entities.

How to answer:

Give the performance and predictability reasons, mention serialization, and offer the alternative you would use. Acknowledge where lazy loading can be acceptable, such as small desktop tools.

AHow would you design soft delete and multi-tenancy filtering so no query can forget them?design

Put both rules in named global query filters on every affected entity, set the tenant from the request through the DbContext, and allow switching a filter off only in specific admin or repair code paths. Add database-side protection too, such as row-level security or filtered views for tenancy, and tests that fail if an entity lacks the filter.

How to answer:

Cover the EF Core mechanism, the source of the tenant value, the controlled escape hatch, defense in depth in the database, and automated checks. Module 13 builds the multi-tenant version.

EF Core performance

FWhat does AsNoTracking do, and when should you use it?concept

It tells EF Core not to keep snapshots of the loaded entities for change tracking. Use it for read-only queries such as lists, reports, and searches. Loading 10,012 students took about 65-77 ms with it and 376-456 ms without it, with identical SQL.

FWhat is the N+1 problem?concept

Running one query for a list and then one more query for each item: 1 + N round trips. It often hides in a loop or behind lazy loading. Fix it with one query that returns everything, such as an Include or a projection with a subquery: 51 queries became 1 for a section's average marks.

FHow do you page results with EF Core?coding

Order the query, then use Skip((page - 1) * pageSize).Take(pageSize), which becomes OFFSET and FETCH in SQL. Return the total count for page numbers, and end the ordering with a unique column such as Id, so rows never repeat or disappear between pages.

MWhy is a projection to a DTO often better than loading entities?concept

It reads only the columns the DTO needs, creates no entities, and is never tracked. It also keeps internal columns, such as audit fields, away from the screen or API. Use entities when you will change and save them; use projections for everything that only reads.

MWhat are ExecuteUpdateAsync and ExecuteDeleteAsync, and what do they skip?concept

They send one UPDATE or DELETE statement for every row matching a LINQ query, without loading entities. Graduating 1,006 students took 1 command instead of 25. They skip the change tracker, entity rules, and anything your SaveChanges logic does, such as setting audit columns, and tracked objects in memory are not refreshed.

MWhat is a cartesian explosion, and how does AsSplitQuery help?concept

Including several collections in one query repeats each parent row for every combination of child rows, so the result can grow enormously. AsSplitQuery() loads each collection with its own query. The trade-off is extra round trips and possible inconsistency if data changes between the queries.

SA page in the SMS is slow, and the team blames EF Core. How do you investigate?scenario

Measure first: log the SQL and count the queries for one page load. Many similar queries mean N+1; one huge query may mean too many includes or columns; a slow single query needs its execution plan and indexes. Then apply the matching fix and measure again with the same data.

How to answer:

Give a method, not a list of tips: measure, classify the cause, fix, and verify. Mention tools such as the EF Core command log, query counters, and SQL Server execution plans.

SWhen would you use a compiled query, and what does it actually save?concept

For very frequent queries with the same shape, such as a lookup by key on every request. It saves EF Core's work of matching the LINQ expression to its cached SQL, not the database time. On SchoolDb, 1,000 lookups were about 20% faster. For ordinary queries, the extra code is not worth it.

How to answer:

State what is cached anyway, what compiling removes, and give a measured gain to keep it in proportion.

AHow would you set data-access performance rules for a team, so problems are caught before production?design

Agree on defaults: projections for reads, no lazy loading, paging on every list, bulk methods for simple mass changes. Log slow queries and query counts per request in every environment, add tests or alerts that fail when a request exceeds a query budget, and run load tests on realistic data volumes such as 10,000 students before release.

How to answer:

Combine coding standards, automated detection, and production monitoring. Mention a realistic data set and query budgets per endpoint.

Testing

FWhat is the difference between a unit test and an integration test?concept

A unit test checks one class's logic alone, with fakes for its dependencies, and runs in milliseconds. An integration test checks parts working together, such as a repository with the real SQL Server, so it finds wrong SQL, mapping, and constraints that fakes cannot.

FWhat is the difference between [Fact] and [Theory] in xUnit?coding

A [Fact] is a test with no inputs. A [Theory] runs once for each set of inputs supplied by [InlineData] rows or a [MemberData] property; each set is reported as its own test. The fee tests use a theory for zero, negative, and too-large amounts.

FWhat does Arrange, Act, Assert mean?concept

A structure for each test: Arrange sets up the objects and data, Act calls the one behaviour being tested, and Assert checks the result. It keeps tests short, readable, and focused on one behaviour.

MWhat is a fake, and how is it different from a mock?concept

A fake is a simple working implementation, such as a repository that stores students in a list. A mock is usually generated by a library and set up with expected calls and answers. Fakes are easy to read and reuse; mocks are handy for checking interactions. Both depend on the code using interfaces.

MHow do you keep integration tests from leaving data in the database?coding

Run each test inside a transaction that is rolled back. With TransactionScope created with TransactionScopeAsyncFlowOption.Enabled and never completed, every connection opened inside joins the transaction, whatever the tool, and disposal rolls it back. Alternatives are a fresh database per run or deleting test data, both slower or more fragile.

MWhat is a regression test? Give an example.concept

A test written for a bug that already happened, so it cannot come back unnoticed. In SchoolApp, an invoice loaded without its payments showed the full balance; a test now loads Diya's partly paid invoice and checks that the balance is 25,500.

SYou have three repository implementations. How do you make sure they behave the same?design

Write one integration test class against the interface, and run every test once per implementation with a theory and MemberData. Four tests became twelve for ADO.NET, Dapper, and EF Core. Where behaviour legitimately differs, such as exception types, assert on what matters to callers or translate the differences in the data layer.

How to answer:

Describe the shared contract tests, how inputs select the implementation, and what to do about differences the tests uncover.

SYour integration tests pass alone but fail when run together. What do you check?scenario

Shared state: tests that rely on data left by others, missing rollbacks, identity or sequence values assumed to be fixed, or a transaction lost after await because the scope was not created with async flow. Make each test arrange its own data, roll back everything it writes, and never assume run order.

How to answer:

List the likely causes, explain how to confirm each (run in a different order, inspect the data), and give the structural fix rather than ordering the tests.

AHow would you design a test strategy for a system like the SMS, from unit tests to production?design

Many fast unit tests for rules and services with fakes; integration tests for every repository and query against a database built from the real scripts; a few end-to-end API tests for key flows such as admission and fee payment; and data-consistency checks. Run unit tests on every change, integration tests in CI, and keep realistic data volumes for performance tests.

How to answer:

Use the test pyramid, say what each level catches and when it runs, and mention test data, database setup in CI, and how failures block a release.

Transactions and concurrency

FHow does EF Core use transactions when you call SaveChangesAsync?concept

Each SaveChangesAsync call runs all its INSERT, UPDATE, and DELETE statements in one transaction: either all are saved or none. Taking a payment saved the payment and the invoice's new status together. For several saves or mixed raw SQL, use Database.BeginTransactionAsync().

FWhat is the lost update problem?concept

Two users read the same data, both change it based on what they read, and the second save overwrites or contradicts the first. Two clerks each took 6,000 from an invoice with 6,000 due, because both screens showed 6,000; without a check, the invoice ended paid 16,000 of 10,000.

FWhat is a ROWVERSION column in SQL Server?concept

A binary value that SQL Server changes automatically on every update of the row; you never set it. Comparing the version you read with the current one tells you whether someone changed the row in between, which is the basis of optimistic concurrency.

MWhat is the difference between pessimistic and optimistic concurrency?concept

Pessimistic concurrency locks the data while working, so nobody else can change it, as usp_RecordFeePayment does with UPDLOCK. Optimistic concurrency takes no lock and checks at save time that the data has not changed, such as with a rowversion. Optimistic suits screens where users think between reading and saving; pessimistic suits short operations with frequent conflicts.

MHow do you add optimistic concurrency to an entity in EF Core?coding

Map a ROWVERSION column as a concurrency token with IsRowVersion(), either on a byte[] property or as a shadow property, builder.Property<byte[]>("RowVersion").IsRowVersion(). EF Core then adds AND RowVersion = @original to every UPDATE and DELETE, and throws DbUpdateConcurrencyException when no row matches.

MWhat happens to tracked entities when you roll back an EF Core transaction?concept

Nothing: the rollback undoes the database, but the objects keep their changed values, and the change tracker treats them as saved. The cancelled invoice still said Cancelled in memory while the database said Unpaid. Discard the DbContext and reload after a rollback.

SA clerk gets a concurrency error when taking a fee payment. What should the application do?scenario

Not show the raw exception. Translate DbUpdateConcurrencyException into a clear error, such as 50014 "the invoice was changed by someone else", reload the invoice so the clerk sees the current balance, and let them decide again. Never retry a money operation automatically with stale values.

How to answer:

Cover translation, reloading, and user decision, and explain why automatic retry or "client wins" is wrong for payments, while it may be fine for low-risk fields.

SWhen do you need an explicit transaction in EF Core instead of relying on SaveChanges?concept

When one business operation needs several SaveChangesAsync calls, mixes EF Core with raw SQL or another tool, or must read and write under one isolation level. Keep it short, commit at the end, and roll back on any error. If connection retries are enabled, run the transaction inside the execution strategy, because retries cannot replay a user-started transaction.

How to answer:

Give concrete triggers, show the begin, commit, rollback shape, and mention the execution strategy caveat and why long transactions hurt concurrency.

AHow would you choose between ADO.NET, Dapper, and EF Core for a new system like the SMS?design

Default to EF Core for everyday work with rules, because units of work, concurrency tokens, and LINQ remove much code and many bugs. Use Dapper for heavy reports where hand-tuned SQL matters, and ADO.NET for special cases such as bulk copy or streaming. Keep all of them behind repository interfaces, and keep critical rules in the database too.

How to answer:

Decide by workload, not by preference; mention mixing tools in one solution, shared transactions, team skills, and measurement before switching tools.

EF Core migrations

FWhat is an EF Core migration?concept

A C# class, written by dotnet ef migrations add, with an Up method that changes the database to match the model and a Down method that undoes it. EF Core records applied migrations in the __EFMigrationsHistory table, so database update runs only the ones a database does not have yet.

FWhat is the difference between database-first and code-first?concept

Database-first: the database is designed in SQL, and EF Core reads it. Code-first: the C# classes are the design, and migrations create and change the database. Database-first suits shared or older databases; code-first suits a database that one application owns.

FWhich dotnet ef commands do you use day to day with migrations?coding

migrations add <Name> to create one, migrations script to see its SQL, database update to apply all pending ones, database update <Name> to go back or forward to one, migrations remove to delete the last unapplied one, and migrations list to see them.

MWhy must you read a migration before applying it? Give examples.scenario

EF Core guesses from the model difference, and some guesses lose data. A rename combined with another change becomes DropColumn plus AddColumn. A new required foreign key gets default 0 that matches no row. Defaults such as cascade delete may not be what the business wants. Read Up, Down, and the SQL, and fix them.

MHow do you write a data migration, for example moving a text column into a new table?coding

Edit the generated migration: create the new table, copy the data with migrationBuilder.Sql, add and fill the new key column, and only then drop the old column and add the foreign key. Write Down to move the data back. Wrap hand-written SQL in EXEC(N'...') so idempotent scripts still compile, and test both directions.

MHow do you apply migrations to a production database?concept

Not from the app at startup. Generate an idempotent script (migrations script --idempotent) for a reviewer or DBA to run, or build a migration bundle (migrations bundle) that the release pipeline runs with the production connection string. Both skip migrations already in __EFMigrationsHistory.

SShould an application call Database.Migrate() when it starts?design

Usually not in production. EF Core 9 and later take a lock so two instances do not both migrate, but the app's login then needs permission to change the schema, a long migration delays start-up, and a failed migration stops the app from starting. Run migrations once in the release, with a script or bundle, under a separate login.

How to answer:

Mention the lock, then permissions, start-up time, failure handling, and the alternative.

SHow do you keep migrations healthy in a team where several developers change the model?scenario

One kind of change per migration, reviewed in pull requests with its SQL. Never edit or remove a migration others have applied; add a new one. Resolve snapshot merge conflicts carefully and run migrations has-pending-model-changes in the build so a model that disagrees with the migrations fails CI. Test migrations, including Down, against a copy of real data before release.

How to answer:

Cover small migrations, review, never rewriting applied ones, snapshot conflicts, CI checks, and testing.

AHow do you change a large production database without downtime?design

Use expand and contract: first add new structures without breaking the old ones (new nullable columns or tables, both written by the app), backfill data in batches, switch reads to the new structure in a release, and only later remove the old columns. Keep every step backward compatible with the running version, avoid long blocking operations (online index builds, batched updates), and have a tested rollback for each step.

How to answer:

Explain expand and contract, compatibility between versions, batching, locking, and rollback per step.