Business Central Cloud | Performance & SetCurrentKey

Imagine the following scenario:

You are the product owner of an industry specific solution that is used by dozens of companies with the same codebase. One day you get an email from a project manager telling you about a performance issue that they have at a specific implementation.

After careful investigation using Application Insights you find out that this customer has an issue in a part of your application where all other customers run just fine.

How is that possible?

The answer might be data distribution in the database. The expensive term that SQL Server specialists are using for this is “cardinality“.

If you implement Business Central for a webshop where customers sporadically buy items the cardinality of Customer No. can be equal to Item No.

If the same webshop now sells the same items over and over again to the same customer the number of records you’ll find with that filter may result in dozens of records and you might want to add a filter on “open” or the current Inventory Period.

Make SQL Server use the right Index

As I wrote yesterday you can now add indexes to your App using Index Packages. Keep the number of indexes in your AppSource App to only nessesairy indexes and add new ones based on the need during the implementation,

The big question is, will SQL Server/SQL Azure actually use the index?

Here the answer is SetCurrentKey

The Myth

For a long time there seems to be a myth in our ecosystem that with Business Central running on SQL SetCurrentKey is no longer important.

This statement is wrong. It is very important.

The reason why people think it can be removed is that SQL Server keeps statistics of your data and it will determine the index based on your filters and knowing the cardinality of your values.

OPTIMIZE FOR UNKNOWN

For Business Central this feature has been disabled by adding a query hint. This means statistics are a lot less important for determining the index.

ORDER BY

With statistics out of the picture the Order By clause becomes more important and this is converted directly from SetCurrentKey

SQL Server will look at your ordering and compare the Order By to the Clustered Index and then determine if it makes sense to use an index or not.

SetCurrentKey ≠ Key

Since a very long time it is allowed in AL to use SetCurrentKey with ANY field in a table, even a flowfield.

Needless to say that if you do a SetCurrentKey on fields that don’t have an index there will be a performance decrease.

Customize SetCurrentKey

In my previous post I learned you how to customize the keys. Now let’s look at how you can implement a new key in a codebase managed on AppSource.

For this we will look at the Microsoft BaseApp. Codeunit Whse.-Purch. Release.

        PurchLine.SetCurrentKey("Document Type", "Document No.", "Location Code");
        PurchLine.SetRange("Document Type", PurchHeader."Document Type");
        PurchLine.SetRange("Document No.", PurchHeader."No.");
        PurchLine.SetRange(Type, PurchLine.Type::Item);
        PurchLine.SetRange("Drop Shipment", false);
        PurchLine.SetRange("Job No.", '');
        PurchLine.SetRange("Work Center No.", '');
        OnAfterReleaseSetFilters(PurchLine, PurchHeader);
        if PurchLine.FindSet() then begin

The Event Publisher OnAfterReleaseSetFilters allows you to change the SetCurrentKey and influence which index SQL Server might use.

Be Careful!

Adding events like this to your App is like handing a PowerTool to a toddler if it is not used in a correct way.

But used in a right way it allows you to do performance tuning in cloud scenario’s.

Leave a comment

Do you like the blogs? Then please leave a comment. I am writing them as I am recovering from surgery and they distract me from the pain and being bored to death,.. Hopefully there will be a new blog tomorrow with an update from MARS…

Girls Just Want to Have Fun,,,

Advertisement

4 Comments

  1. qnito says:

    Great blog!!!! Please, continue distracting you.

    Liked by 1 person

    1. Only your blog post made me indirectly aware of the last bullet point within this docs article section:
      https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-setcurrentkey-setrange-setfilter-getrangemin-and-getrangemax-methods#setcurrentkey-method

      I’ve never seen a SetCurrentKey used with the return value, nor an error message due to a failed SetCurrentKey …

      Get well and pain free soon!

      Liked by 1 person

  2. Sorry, if i do not understand something here.
    Correct me if i misunderstood you.
    You wrote, that SetCurrenKey is important to advise SQL- Server to use the right index. I just run a test with BC14. In my test the SSMS- Monitor shows that SQL server always uses Order By with OPTIMIZE FOR UNKNOWN.
    That shows to me that SetCurrentkey is useless, because SQL-Server uses it’s overall statistics and not the statistics for specific query values.

    But perhaps newer Versions behave different. So perhaps you can explain the difference.

    Like

    1. Yes you are correct, SetCurrenyKey converts into Order By and by that determines the Index.

      Like

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.