Der EntireTable-Cache-Entscheidungshelfer

Mein erster ernsthafter Beitrag beschäftigt sich mit dem Caching von Tabellen in AX 2012. Du weißt schon alles darüber? Lies trotzdem weiter!

Das Property CacheLookup

Ich hoffe schwer, dass dir das Property CacheLookup, das man an jeder Tabelle setzen kann (sollte), bereits bekannt ist. Man hat die Auswahl zwischen den Werten

  • None
  • NotInTTS
  • Found
  • FoundAndEmpty
  • EntireTable

Im MSDN ist das alles ganz gut dokumentiert, im Artikel Single-record Caching [AX 2012]. Hier geht es heute nur um die Einstellung EntireTable.

Das Problem

Im MSDN wird der EntireTable-Cache im Artikel Set-based Caching [AX 2012] konkretisiert. Dort findet sich auch der wichtige Hinweis

Avoid using EntireTable caches for large tables because once the cache size reaches 128 KB the cache is moved from memory to disk. A disk search is much slower than an in-memory search.

Unglücklicherweise stimmt das gar nicht! Tatsächlich kann man die Größe des Cache einstellen (siehe nächster Abschnitt).

Man sollte vorsichtig mit dem Wert EntireTable für das Property CacheLookup sein, weil man damit eine Verbesserung der Performance erzielen möchte, aber tatsächlich unwissentlich eine Verschlechterung verursachen kann. Es ist aus Performancegesichtspunkten sehr kostspielig, wenn der Cache vom Arbeitsspeicher auf die Platte ausgelagert wird!

Weil aber die Verwendung des EntireTable-Cache in den richtigen Konstellationen sehr zuträglich ist: Was sind diese richtigen Konstellationen? Wann genau ist die Schwelle erreicht, ab der eine Auslagerung stattfindet, weil Tabelle X die maximal zulässige Größe von nnn KB erreicht hat? Hierbei kann ich für Abhilfe sorgen!

Einstellen der Cachegröße

Serverkonfiguration
Die Cachegröße der gesamten Tabelle (welch fantastisches Label) kann im Formular Serverkonfiguration eingestellt werden, das über Systemadministration > Einstellungen > System aufrufbar ist. Offensichtlich können voneinander abweichende Werte pro AOS vergeben werden, was meiner Meinung nach absolut keinen Sinn ergibt. In einem solchen Fall muss man sich nach dem kleinsten eingestellten Wert richten, was wiederum dazu führt, dass alle anderen unnötig hohe Werte vorweisen…

Der Standardwert in AX 2012 T3 liegt bei 96 KB.

Die Mathematik

…hinter dem Ganzen ist denkbar einfach. Jeder Datensatz benötigt in Abhängigkeit der Art und Anzahl der definierten Felder eine gewisse Menge an Platz im Speicher. Hat man zum Beispiel eine Tabelle, deren Datensätze genau 1 KB groß sind, kann man maximal 96 Datensätze abgespeichert haben, bevor der EntireTable-Cache auf die Platte ausgelagert wird.

Das Tool

Als Entwickler möchte man natürlich am liebsten ein Tool, das in die Entwicklungsumgebung integriert ist. Bekommst du! Wir integrieren den EntireTable-Cache-Entscheidungshelfer einfach ins Kontextmenü des AOT. Wie das gemacht werden kann, ist ebenfalls im MSDN dokumentiert (siehe How to: Add Items to the AOT Add-Ins Menu [AX 2012]). Wir benötigen dafür lediglich eine kleine Klasse, ein Action-Menu-Item und zwei kleine Anpassungen (oder zu Deutsch auch „Customizations“ genannt).

Class XltyCacheDecisionHelper

class XltyCacheDecisionHelper extends RunBase
{
}
 
public static client server ClassDescription description()
{
    return 'Analyse CacheLookup';
}
 
public static void main(Args args)
{
    SysContextMenu sysContextMenu;
    TreeNode treeNode;
    TableId tableId;
    if (SysContextMenu::startedFrom(args))
    {
        sysContextMenu = args.parmObject();
        treeNode = sysContextMenu.first();
        if (treeNode)
        {
            tableId = SysTableBrowser::treeNode2TableId(treeNode);
        }
    }
    else
    {
        tableId = pickTable();
    }
    if (tableId)
    {
        XltyCacheDecisionHelper::showEntireTableCacheAnalysis(tableId);
    }
}
 
private static void showEntireTableCacheAnalysis(TableId _tableId)
{
    SysDictTable sysDictTable = new SysDictTable(_tableId);
    real recordSize = sysDictTable.recordSize();
    real maxBytesForEntireTableCache = 1024 * 96; // default server setting is 96kb per table
    int maxRecordsEntireTableCache = real2int(maxBytesForEntireTableCache / recordSize); // precision loss is wanted here - cut decimals
    info(strFmt('Datensatzgröße in Tabelle %1 ist %2 Bytes -> %3 ist die maximale Anzahl Datensätze für EntireTable-Caching ohne, dass ausgelagert wird!', sysDictTable.name(), recordSize, maxRecordsEntireTableCache));
}

Action-Menu-Item
Wir benötigen ein Action-Menu-Item, das der Einfachheit halber auch XltyCacheDecisionHelper heißen möge und auf die Klasse verweist.

Anpassen der Klasse SysContextMenu, Methode verifyItem
Finde die Stelle, an der im Switch-case der Case MenuItemType::Action abgehandelt wird und ergänze den folgenden neuen Case

    case menuitemActionStr(XltyCacheDecisionHelper):
        isValid = _firstType == UtilElementType::Table && !firstNode.AOTIsOld();
        break;

Anpassen des Menüs SysContextMenu

Analyse CacheLookup

Füge das Action-Menu-Item XltyCacheDecisionHelper dem Menü SysContextMenu hinzu. Thematisch sinnvoll wäre z.B. in der Nähe des Tabellen-Browser.

Das war’s! Die Information, die du brauchst, um eine bessere Entscheidung treffen zu können, ob EntireTable-Caching verwendet werden kann oder nicht, ist jetzt direkt im AOT verfügbar!

Ergänzend

Das Ganze geht davon aus, dass der minimale Wert der Cachegröße der gesamten Tabelle bei 96 KB liegt. Man könnte als Ausbaustufe natürlich über die Serverkonfigurationen lesen und den niedrigsten Wert zur entsprechenden Verwendung ermitteln.
PLUS: Keine Gewähr und bitte nicht unbedarft in Produktivsystemen zum Einsatz bringen. Ergibt ja auch keinen Sinn, weil es sich um ein Entwicklungswerkzeug handelt? Stimmt, aber man weiß ja nie 🙂

Update

Mittlerweile habe ich das Ganze verfeinert und auch einen Download zur Verfügung gestellt. Bitte hier entlang!

Schreibe einen Kommentar