Monday, 7 September 2026

BC 29 lets a single index span base table and table extension fields

 Business Central 2026 release wave 2 removes a constraint that has shaped how we index extended tables since table extensions existed. In version 29, a key defined in a table extension can contain fields from the base table and fields from the extension at the same time.

That sounds small. In practice it retires one of the most common workarounds in AL development.

The constraint

Microsoft Learn has always been clear about this one. Keys defined in a table extension are secondary keys, because a table extension inherits the primary key of the table it extends. Those secondary keys can include fields from the base table, or fields from the table extension, but a single key cannot include fields from both. Each key has to be all base table fields or all fields from the extension in which it is defined.

Version 18 improved half of the problem. Before that, you could only build keys on the fields your extension added. From version 18 onward you could also add a key on fields that already existed in the base table, which solved a real category of performance issues. The standard example is External Document No. on posted document tables, where the base app key combines it with another field and a direct lookup has no useful index.

What version 18 did not solve is the mixed case. And the mixed case is the one that keeps coming up in real projects.

What the scenario looks like

Say you add a Region Code field to Sales Invoice Header for a customer with a regional reporting requirement. A user wants a list filtered by Sell-to Customer No. and sorted by Region Code, on a table with a few million rows.

Sell-to Customer No. lives in the base table. Region Code lives in your extension. You cannot put them in one key.

Why the constraint existed

This was never a Business Central design decision. It was SQL.

Under the old data model, fields added by table extensions were stored in a companion table, separate from the base table, joined at read time on the primary key. Version 23 improved that by consolidating all extensions to a table into a single companion table, so the server never needed more than one join instead of one per extension. But there were still two physical tables.

SQL Server cannot build a single index across two tables. That is the entire reason a key could not mix base fields with extension fields. The platform was passing the database's answer back to you.

Version 29 changes the storage. According to the release notes, all fields on an AL table are now stored in the same table in the database, and Microsoft attributes the new cross-boundary key capability directly to that change.

Once the fields are physically together, the objection disappears. One table, one index, no problem.

How to verify it yourself

You do not need to wait for the on-premises release to check this, and you do not need database access. The test is a compile.

tableextension 60400 "MPA Sales Invoice Header" extends "Sales Invoice Header"

{

    fields

    {

        field(60400; "Region Code"; Code[20])

        {

            Caption = 'Region Code';

            DataClassification = CustomerContent;

        }

    }

 

    keys

    {

        // "Sell-to Customer No." belongs to the base table, owned by the

        // Base Application. "Region Code" is declared right here.

        // One key, fields from both sides of the boundary.

        key(CustomerRegion; "Sell-to Customer No.", "Region Code") { }

    }

}

Compile it twice, once against symbols from a version 28 sandbox and once against symbols from a version 29 preview sandbox. On version 28 this fails, which is the documented behaviour and what makes the comparison meaningful.

BC28:



The property 'CustomerRegion' can only be set if the specified fields are from the same table.ALAL0423

Key CustomerRegion: "Sell-to Customer No.", "Region Code" 


BC29:

What this changes in practice

Some slow lists become fixable without a redesign. Any place a user filters on a standard field and sorts on yours, or the reverse, is now an indexing problem rather than an architecture problem.

Reporting extractions get simpler. Custom analysis views and extracts that combine base and extension fields have had no supported index path. Now they do.

 

What to be careful about

The constraint going away does not make indexes free.

There is still a limit of 40 keys per table. That limit predates this change and has not moved. Cross-boundary keys are about to look very attractive, and on a popular table with several apps installed, that budget gets consumed faster than anyone plans for.

Every index costs writes. An index that makes one list fast makes every insert and modify on that table slower. On Sales Invoice Header, Item Ledger Entry, or G/L Entry, that is not a theoretical cost. Measure the write path, not only the read you were trying to fix.

Adding an index to a base table means building it during schema sync. On a large production table, that is an upgrade window question rather than a deployment detail. Test the install time on a copy of real data volumes, not on Cronus.

Nobody owns the aggregate. Nothing stops three separate apps each adding a cross-boundary index to Customer. Each decision is defensible on its own, the write cost is shared, and no single publisher sees the whole picture. If you build for multiple ISV environments, this belongs on the list of things you check.

Where this sits right now

The version 29 public preview runs from the first week of September until general availability in the first week of October 2026, and it applies to online sandbox environments only. Not production, not on-premises. Microsoft has said on-premises detail will be added to the documentation when 29.0 goes generally available, and preview sandboxes are deleted around thirty days after that.

So none of this is production guidance yet. But the compile test can be run today, it costs almost nothing, and it answers the question well before anyone gets to look at the SQL. If you maintain apps that extend high volume tables, it is worth knowing now which of your workarounds you are about to be able to delete.

 

No comments:

Post a Comment