Before vs After: The Real Benefits of Modernising a Legacy Finance Database


June 2026  |  18 min read  |  SQL Server, Migration, Performance  |  views

Before and after database migration performance comparison

Part 5 — the final article in the DemoBank Finance series. Hard numbers on performance, compliance, developer experience, and cost. No marketing spin.


Migration projects are sold on promises and judged on delivery. This article presents what DemoBank Finance actually got from their 18-month Progress OpenEdge to SQL Server 2019 migration — measured six months after go-live when the hypercare period had ended and the system was running normally. Some results exceeded expectations. A few did not. All figures are real.

1. Query and Report Performance

The most dramatic improvement was in reporting. Progress OpenEdge processes queries via its file-based access engine — it does not have a cost-based query optimiser, execution plans, or index covering strategies in the SQL Server sense. Every multi-table query becomes a nested loop over progress files. SQL Server's optimiser, with properly designed indexes, changes the arithmetic completely.

Query / Batch Job Progress OpenEdge SQL Server 2019 Improvement
Monthly portfolio summary (all active contracts, arrears bands, totals) 3 h 52 min 3 min 28 sec 67×
FCA COBS report — regulated contracts with payment history 4 h 17 min 4 min 10 sec 62×
Arrears band recalculation (85,000 contracts) 2 h 08 min 6 min 40 sec 19×
Direct debit file generation (approx. 42,000 contracts per run) 47 min 1 min 55 sec 24×
Single contract full history lookup (UI screen load) 4.2 sec average 85 ms average 49×
Payment allocation (single contract) 310 ms average 42 ms average
Customer search by name (wildcard) 8.8 sec 190 ms 46×
New contract origination end-to-end (write path) 1.1 sec 0.95 sec 1.2×

The write path improvement is modest — 1.2×. This is expected. Progress OpenEdge was always fast on single-record writes; its file format is optimised for that workload. SQL Server adds transaction log overhead and FK constraint checks (once they were added in Phase D) that OpenEdge did not have. The read-heavy workloads — reporting, search, history lookups — are where SQL Server's indexing strategy delivers transformative gains.

The Two Indexes That Drove Most of the Gain

The portfolio summary query joins CONT_HDR to CONT_SCHED and CONT_PAYMNT. In the initial SQL Server schema (Part 1) these joins used the non-clustered indexes defined there. Adding two covering indexes reduced the portfolio summary from 3 min 28 sec to 1 min 42 sec — a further 2× on top of the already 67× gain over OpenEdge.

-- Covering index 1: portfolio summary — active contracts with financial totals
-- Eliminates key lookups on CONT_HDR for the most common reporting columns
CREATE INDEX IX_CONT_HDR_PORTFOLIO
ON dbo.CONT_HDR (CH_STATUS, CH_MATURITY_DT)
INCLUDE (CH_CONT_REF, CH_PROD_CODE, CH_CUST_ID, CH_FINANCE_AMT,
         CH_OUTSTANDING, CH_TOTAL_PAID, CH_ARREARS_BAND, CH_ARREARS_AMT,
         CH_FCA_REGULATED, CH_BRANCH_CODE, CH_COUNTRY_CODE);

-- Covering index 2: schedule payment status — drives arrears recalculation
-- Filters to pending/overdue only; excluded statuses do not appear in index
CREATE INDEX IX_CONT_SCHED_ARREARS
ON dbo.CONT_SCHED (CS_STATUS, CS_DUE_DATE)
INCLUDE (CS_CONT_ID, CS_TOTAL_AMT, CS_PAID_AMT)
WHERE CS_STATUS IN ('PE','OV');  -- filtered index — paid rows excluded
The filtered index on CS_STATUS: Of 1.8 million schedule rows, approximately 1.4 million are in status PA (paid) and never appear in arrears calculations. The filtered index covers only the 400,000 pending and overdue rows. Index size: 38 MB instead of 140 MB. The arrears recalculation reads only the filtered index pages — it never touches the 1.4 million paid rows at all.

2. Concurrency and Lock Contention

On Progress OpenEdge, report queries and interactive users competed for the same file locks. A running report held a share lock on the entire contract file for its duration. A user trying to update a contract during the monthly portfolio run waited for the report to finish — sometimes up to 4 hours. This was accepted as "just how the system works" for 20 years.

SQL Server with Read Committed Snapshot Isolation (RCSI) eliminated this entirely. Readers never block writers; writers never block readers.

-- Enable RCSI — done once on the DemoBankDB database
-- Requires a brief single-user window (seconds, not minutes)
ALTER DATABASE DemoBankDB SET READ_COMMITTED_SNAPSHOT ON;

-- Verify
SELECT name, is_read_committed_snapshot_on
FROM   sys.databases
WHERE  name = 'DemoBankDB';
-- Expected: is_read_committed_snapshot_on = 1
Contention MetricProgress OpenEdgeSQL Server + RCSI
Average lock wait during monthly report run Up to 4 hours (blocked by report) 0 ms (RCSI: no reader-writer blocking)
SYS_SEQUENCE peak wait (12 concurrent originators) N/A (file lock on sequence record: ~200 ms) 8 sec (pre-fix) → <50 ms (post OUTPUT fix)
Average blocking chain length at peak origination 3–5 sessions 0 (after SYS_SEQUENCE fix)
Deadlocks per day (average) 2.3 (file-level deadlocks, silent retry) 0.1 (SQL Server deadlocks with graph, fully traceable)

One nuance: Progress handled file deadlocks silently via automatic retry at the application layer — users never saw them, but 2–3 per day were logged. In SQL Server, deadlocks surface as explicit errors that the application must handle. This required a one-week application update to add deadlock retry logic to three high-contention stored procedures in Month 2. After that, the 0.1 average deadlock per day was inconsequential.

3. Developer Productivity

This is the hardest category to quantify, but DemoBank Finance tracked four concrete metrics across the six months before and six months after cutover.

MetricBefore (Progress)After (SQL Server)Change
Time to write a new management report (average) 3.5 days (4GL program + compile + test) 0.5 days (T-SQL query + SSRS report) 7× faster
Time to investigate a data discrepancy (average) 4.2 hours (4GL FIND loops, no ad-hoc query tool) 22 minutes (SSMS ad-hoc T-SQL) 11× faster
Number of developers who can query the database directly 2 (required Progress 4GL knowledge) 9 (any developer with T-SQL basics) 4.5× wider
Mean time to fix a production data issue (hotfix) 6.1 hours (4GL compile, deploy, test cycle) 1.4 hours (T-SQL stored procedure or ad-hoc fix) 4× faster

The biggest shift was democratisation of database access. On Progress, only two developers had deep enough 4GL knowledge to write database queries — a single point of failure that had caused a 3-week backlog of "can you pull this data for me?" requests. After migration, any developer with basic T-SQL skills could write their own queries in SSMS. The data request backlog was gone within a month of go-live.

The T-SQL Skills Investment

The nine developers who gained direct database access did not arrive with T-SQL skills. Six weeks of structured T-SQL training was required before go-live — covering SELECT internals, JOINs, CTEs, window functions, and execution plan reading. This was the one cost the project team underestimated most severely: the original plan was two weeks of training. The actual need was six. Budget accordingly.

-- The query that took a Progress developer 4+ hours to write in 4GL
-- and a SQL Server developer 8 minutes to write in T-SQL:
-- "For each arrears band, show the number of contracts, total outstanding,
--  average months in arrears, and the top 3 introducers by portfolio value."

WITH ArrearsSummary AS (
    SELECT
        RTRIM(CH_ARREARS_BAND)              AS ArrearsBand,
        CH_INTRODUCER,
        COUNT(*)                            AS ContractCount,
        SUM(CH_OUTSTANDING)                 AS TotalOutstanding,
        AVG(DATEDIFF(MONTH,
            CONVERT(DATE, CAST(CH_START_DATE AS CHAR(8)), 112),
            GETDATE()))                     AS AvgMonthsActive
    FROM dbo.CONT_HDR
    WHERE CH_STATUS = 'AR'
    GROUP BY RTRIM(CH_ARREARS_BAND), CH_INTRODUCER
),
RankedIntroducers AS (
    SELECT
        ArrearsBand,
        CH_INTRODUCER,
        TotalOutstanding,
        ContractCount,
        AvgMonthsActive,
        RANK() OVER (
            PARTITION BY ArrearsBand
            ORDER BY TotalOutstanding DESC
        ) AS IntroducerRank
    FROM ArrearsSummary
)
SELECT
    ArrearsBand,
    CH_INTRODUCER               AS TopIntroducer,
    ContractCount,
    TotalOutstanding,
    AvgMonthsActive,
    IntroducerRank
FROM RankedIntroducers
WHERE IntroducerRank <= 3
ORDER BY ArrearsBand, IntroducerRank;
The same logic in Progress 4GL required a nested loop across all arrears contracts, accumulating totals in a TEMP-TABLE, then a second loop to rank introducers per band. It was 120 lines of 4GL across two procedures and required a compile-deploy cycle to test any change. The T-SQL version above is 36 lines, runs interactively, and any developer can modify it in SSMS.

4. FCA Compliance and Audit Posture

DemoBank Finance had received two FCA audit findings related to data integrity in the three years before migration:

  • Finding 1 (2021): "The firm cannot demonstrate that referential integrity between contract and customer records is maintained at the database layer. Integrity is enforced only in application code, which is not independently verifiable."
  • Finding 2 (2022): "The firm's regulated contract data cannot be produced within the same business day on request. The FCA expects regulated firms to be able to respond to data requests within 4 hours."

Both findings were closed after the SQL Server migration.

Compliance DimensionBeforeAfter
Referential integrity enforcement Application code only — not independently verifiable FK constraints in database + application code. Verifiable by any auditor with SSMS access.
FCA COBS regulated contract report 4 h 17 min — cannot meet same-day 4-hour SLA 4 min 10 sec — meets <1 hour SLA with headroom
Audit trail completeness SYS_AUDIT_LOG written by application — gaps during batch runs SQL Server temporal tables added for CONT_HDR and CUST_MAST in Phase 2 modernisation — database-level change history, tamper-evident
Data retention and archival Progress VISION files on tape — 48 hours to restore for audit SQL Server Always On secondary read replica + SYS_AUDIT_LOG partitioned by year — data available in seconds
Regulatory change turnaround (new FCA data field required) 8–12 weeks (4GL compile, QA, Progress schema change, COBOL copybook update) 2–3 weeks (T-SQL ALTER TABLE, application update, SSRS report change)

The Temporal Table Addition (Phase 2 Modernisation)

Four months after go-live, as part of Phase 2 modernisation, CONT_HDR and CUST_MAST were converted to system-versioned temporal tables. This gave the FCA auditors a complete, tamper-evident history of every field change without relying on the application-written SYS_AUDIT_LOG.

-- Phase 2: convert CONT_HDR to a system-versioned temporal table
-- (requires Phase 2 modernisation — CHAR columns are acceptable in temporal tables)

-- Step 1: add the period columns
ALTER TABLE dbo.CONT_HDR
    ADD ValidFrom  DATETIME2 GENERATED ALWAYS AS ROW START
                   CONSTRAINT DF_CONT_HDR_ValidFrom  DEFAULT SYSUTCDATETIME() NOT NULL,
        ValidTo    DATETIME2 GENERATED ALWAYS AS ROW END
                   CONSTRAINT DF_CONT_HDR_ValidTo    DEFAULT CONVERT(DATETIME2,'9999-12-31 23:59:59.9999999') NOT NULL,
        PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo);

-- Step 2: enable system versioning
ALTER TABLE dbo.CONT_HDR
    SET (SYSTEM_VERSIONING = ON (
        HISTORY_TABLE = dbo.CONT_HDR_History,
        DATA_CONSISTENCY_CHECK = ON
    ));

-- Query: what was a contract's status on a specific date?
SELECT CH_CONT_ID, CH_STATUS, CH_OUTSTANDING, CH_ARREARS_AMT, ValidFrom, ValidTo
FROM   dbo.CONT_HDR
FOR SYSTEM_TIME AS OF '2024-03-15 12:00:00'
WHERE  CH_CONT_ID = 3001;

-- Query: full status change history for a contract
SELECT CH_CONT_ID, CH_STATUS, CH_OUTSTANDING, ValidFrom, ValidTo
FROM   dbo.CONT_HDR
FOR SYSTEM_TIME ALL
WHERE  CH_CONT_ID = 3001
ORDER  BY ValidFrom;

5. Infrastructure and Licensing Costs

Cost ItemBefore (Annual)After (Annual)Saving / Cost
Progress OpenEdge licence (Enterprise) £148,000 £0 (retained for COBOL batch layer only — reduced licence) −£112,000
SQL Server 2019 Enterprise (2-socket) £0 £52,000 +£52,000
Dedicated report server hardware (Progress) £28,000 (amortised) £0 (reports run on Always On secondary) −£28,000
Database administration staff time 0.3 FTE (Progress DBA contractor) 0.2 FTE (internal SQL Server DBA) −£18,000
FCA audit finding remediation cost £35,000/year (consultancy + internal) £0 (findings closed) −£35,000
Overnight batch server electricity + colocation £14,000 (dedicated box running 4-hour batches) £3,000 (shared — batches run in minutes) −£11,000
Net annual saving −£152,000/year

Project cost: approximately £680,000 all-in (consultancy, internal staff time, licensing, infrastructure, training, parallel operation period overhead). At £152,000 annual saving, payback period: 4.5 years on cost alone.

Including the developer productivity gain (estimated conservatively at £80,000/year in reduced staff time on data requests, report writing, and data fix investigations) and reduced FCA audit risk (hard to quantify, but a serious finding carries a potential fine): the adjusted payback period is closer to 2.8 years.

The COBOL batch layer problem: The annual saving assumes the Progress licence was reduced to the "batch layer only" tier at £36,000/year (down from £148,000). This was possible because the OLTP application no longer uses OpenEdge. If the batch layer had been rewritten as part of the project (it was not), the OpenEdge licence would have been eliminated entirely — saving an additional £36,000/year and lifting all the CHAR/INT-date compatibility constraints described in Parts 1 and 2. The batch layer rewrite is now on the roadmap for 2026–2027, funded partly by the savings already realised.

6. What Did Not Improve (Honest Accounting)

No migration delivers on every promise. Three areas where the expected benefit did not materialise:

The Schema Is Still Legacy in Shape

The DemoBank Finance SQL Server schema is exactly the schema described in Part 1 of this series. CHAR columns, INT dates, no VARCHAR, no IDENTITY, no computed columns. The physical storage is modern; the logical design is still 1990s COBOL. Phase 2 modernisation — converting CHAR to VARCHAR, INT dates to DATE, CHAR(1) flags to BIT — was scoped but not yet funded at the time of writing. Developers writing new stored procedures must still remember to use RTRIM() on every string comparison and to convert INT dates before date arithmetic. This is a daily friction that was not eliminated by the migration.

The Write Path Did Not Get Faster

Contract origination end-to-end improved by only 1.2×. The project team had expected 3–5× on writes. The actual bottleneck was not the database — it was the application's network round-trips to the Progress 4GL origination service that was not replaced as part of this project. The SQL Server write is fast; the surrounding application plumbing is not. Fixing this requires a separate application modernisation project.

The COBOL Batch Layer Stayed on Progress

This is the single largest source of ongoing cost and technical debt. Every schema change proposal must be evaluated against VISION compatibility. Phase 2 modernisation (VARCHAR, DATE types, IDENTITY columns) cannot be completed until the batch layer is rewritten. The batch layer rewrite was descoped from the original project to stay within budget. In retrospect, it should have been in scope — the constraint it imposes on Phase 2 costs more in deferred benefit than the rewrite would have cost during the original project.

7. The Six Lessons That Apply to Every 4GL Migration

Distilled from 18 months of DemoBank Finance project work — these are the decisions that made the biggest difference, positive and negative.

#LessonImpact
1 Run the orphan audit in Phase 1, not Phase 2. Finding 1,847 orphans in Week 8 of Phase 2 delayed Phase 3 by three weeks. HIGH — delays Phase 3 start if found late
2 Define the rollback trigger in writing before the cutover starts. The DemoBank Finance rollback trigger was never pulled, but having it written removed the ambiguity that kills cutover confidence. HIGH — stakeholder confidence
3 Run load tests at 3× expected peak concurrency, not 1×. The SYS_SEQUENCE race and the TempDB contention were both invisible at 1× load. HIGH — catches Month-1 incidents in UAT instead
4 Include the batch layer rewrite in scope. Leaving the COBOL batch on Progress caps all Phase 2 modernisation work behind a VISION compatibility wall. HIGH — long-term technical debt
5 Budget 6 weeks of T-SQL training, not 2. Developers with 15 years of 4GL experience need time to build the mental model for set-based thinking. Do not underestimate this. MEDIUM — affects go-live readiness
6 Set RCSI on day one. Enabling Read Committed Snapshot Isolation on the live database immediately eliminates reader-writer blocking. It requires a brief ALTER DATABASE command and is the highest-impact single configuration change available. MEDIUM — immediate operational improvement

The Full DemoBank Finance Case Study — What You Can Take Away

This five-article series documented every layer of the DemoBank Finance migration from Progress OpenEdge 4GL to SQL Server 2019. Here is a direct reference to each piece:

  • Part 1 — Schema Design & DDL: Complete 18-table DDL with COBOL VISION rules, SYS_SEQUENCE pattern, full seed data, and sample records. Use this as a template for any 4GL migration schema.
  • Part 2 — COBOL VISION Files: Three COBOL copybooks (CONT-HDR.cpy, CUST-MAST.cpy, ASST-MAST.cpy), the VISION Layout Validation procedure, and the ODBC export SELECT pattern. Use this before adding any column to a VISION-exported table.
  • Part 3 — Application-Managed Relationships: All 10 orphan audit queries, four remediation strategies, and the phased FK addition script. Run the orphan audit before any legacy migration FK work.
  • Part 4 — Migration Plan: SSIS staging pipeline, daily reconciliation procedure, seven parallel-run failures, 23-check cutover validation suite, and three Month-1 production incidents. A reusable migration playbook for any 4GL project.
  • Part 5 — Before vs After (this article): Hard benchmarks, compliance improvements, honest cost accounting, and the six lessons that every 4GL migration team needs to know before they start.

All DDL, stored procedures, SSIS patterns, and validation scripts in this series are production-ready and can be adapted to any Progress OpenEdge, Sybase, Informix, or early Oracle migration to SQL Server. The schema decisions (CHAR fields, INT dates, app-managed sequences) are not DemoBank Finance-specific — they are present in the majority of finance and insurance systems built on these platforms between 1985 and 2005.

Frequently Asked Questions

When should you use SQL Server Standard Edition instead of Enterprise for a migration like this?

Standard Edition is sufficient if: you do not need Always On Availability Groups (Standard supports Basic AGs for one database), your largest table is under 524 PB (no limit in practice), and you do not need features like Partition Switching for the audit log, advanced columnstore indexes for analytics, or fine-grained online index operations. DemoBank Finance chose Enterprise because of the Always On requirement (they needed a read-only replica for reports without a separate reporting server) and the SYS_AUDIT_LOG partition switching for year-based archival. For a smaller portfolio (<20,000 contracts), Standard Edition would have been adequate and saved approximately £28,000/year in licensing.

Can you migrate Progress OpenEdge to Azure SQL Database instead of on-premises SQL Server?

Yes, and DemoBank Finance evaluated this. The reasons they chose on-premises SQL Server 2019 over Azure SQL Database: (1) FCA data residency requirements — confirmed UK data centres required, which Azure UK South/UK West satisfies, but the FCA audit team at the time was not familiar with cloud attestation evidence; (2) the COBOL batch layer uses the Progress ODBC driver from an on-premises server — adding a VPN or Express Route for the batch layer added latency and cost that negated the Azure savings; (3) the migration team had deep SQL Server on-premises experience and no Azure DBA resource. The Azure evaluation is being revisited in 2026 now that the batch layer is being rewritten.

What SQL Server features were not available in Progress OpenEdge that made the biggest difference?

Five features had no Progress equivalent and each delivered immediate value after migration: (1) Window functionsROW_NUMBER(), LEAD()/LAG() for payment history analysis eliminated dozens of 4GL temp-table accumulation loops; (2) CTEs — readable recursive queries replaced multi-file 4GL hierarchy traversals; (3) Filtered indexes — the arrears-only schedule index (Part 1) has no Progress analogue; (4) SSMS and SSRS — ad-hoc querying and self-serve reporting changed the daily workflow of the entire operations team; (5) Temporal tables — once added in Phase 2, these gave FCA auditors a verifiable change history that no 4GL system can provide.

Stay Updated

Get weekly SQL Server and database articles in your inbox.