Tipps und Tricks für schnelle Datenbanken
Hier erfahren Sie, wie Sie Ihren Datenbanken einen Performance-Boost verpassen können
Zuerst eine kleine Checkliste mit allgemeinen Fragen bzw. Hinweisen:
Wo könnten Engpässe liegen?
Ein Blick in den Prozess-Monitor hilft Ihnen, Stellen aufzeigen, wo Verbesserungen möglich sind.
Kann der konzeptionelle Aufbau der Datenbank optimiert werden?
Schauen Sie sich Ihr Datenmodell an, um evtl. Optimierungspotential zu erkennen. Große, schwere Datenbanken haben längere Zugriffszeiten.
Besteht die Möglichkeit, die Datenbank in kleinere Tabellen, ggf. mit Untertabellen, aufzuteilen?
Nehmen Sie längere Ladezeiten wahr, wenn Sie bestimmte Ansichten aufrufen?
Könnten Sie die Daten in mehrere Ansichten aufteilen, indem Sie die Ansichten filtern? Oder nicht direkt benötigte Spalten ausblenden? Besteht die Möglichkeit, die Anzahl von Spalten mit Formeln zu reduzieren?
Könnten Daten auch gruppiert werden, damit weniger Daten auf einen Schlag geladen werden müssen?
Sind die Skripte optimiert? Wie ist der Zugriff auf bestimmte Daten aufgebaut?
Prüfen Sie Ihre Skripte. Oft ist es möglich, ein Skript in mehrere Skripte aufzubrechen und so die Abläufe zu beschleunigen.
Im nächsten Abschnitt finden Sie ein paar Anregungen, wie Sie Skripte optimieren können.
Tipps und Tricks
Hier zeigen wir Ihnen, wie Sie allein durch den Aufbau Ihres Skripts Zugriffs- und Bearbeitungszeiten verbessern können:
- Warum verschachtelte Schleifen gefährlich sind
- Wie do as ... die Performance verbessern kann
- Warum Sie sparsam mit select umgehen sollten
Warum verschachtelte Schleifen gefährlich sind
Falls Sie select
oder eine for
-Schleife innerhalb einer anderen Schleife verwenden, sollten Sie sich fragen, ob dies tatsächlich notwendig ist.
Kann der verschachtelte Teil unabhängig ausgeführt werden? Dann sollten Sie die Schleifen nacheinander ausführen.
Beispiel
Nehmen wir an, dass Tabelle1 und Tabelle2 jeweils 1.000 Datensätze haben.
let anzahl := 0;
for i in select Tabelle1 do
for j in select Tabelle2 do
anzahl := anzahl + 1endend;
anzahl
Welchen Wert hat anzahl
nach Durchlauf des Skripts (in Zeile 7)?
Antwort: 1.000.000
Denn für jeden der 1.000 Datensätze in Tabelle1 durchlaufen wir jedes Mal alle 1000 Datensätze in Tabelle2.
Beim Verschachteln von Schleifen multiplizieren Sie die Iterationen (m * n).
So geht's besser
Führen Sie – wenn möglich – die Schleifen der Reihe nach aus, dann addieren Sie lediglich die Iterationen (m + n).
let anzahl := 0;
for i in select Tabelle1 do
anzahl := anzahl + 1
end;
for j in select Tabelle2 do
anzahl := anzahl + 1
end;
anzahl
Welchen Wert hat anzahl
in diesem Fall?
Antwort: 2.000
Denn wir durchlaufen erst alle Datensätze der Tabelle1 und dann die der Tabelle2.
Wie do as ...
die Performance verbessern kann
In Ninox unterscheiden wir zwischen lesenden und schreibenden Transaktionen:
- lesende Transaktionen, wie z.B. das Laden einer Tabelle, können gleichzeitig stattfinden
- schreibende Transaktionen, wie z.B. das Hinzufügen von Daten, werden der Reihe nach ausgeführt
Mehr zu Transaktionen und Performance der Skripte optimieren.
Eine häufige Ursache für schlechte Performance sind schreibende Transaktionen, die andere schreibende Transaktionen aufhalten.
Beispiel 1
Dieses einfache Skript erstellt 1.000 Datensätze.
for i in range(1000) do
create Tabelle1
end;
Auf den ersten Blick ist kein Problem erkennbar.
Wenn Sie dieses Skript allerdings in einem Button in der Web-App ausführen, wird für jede Iteration eine eigene Transaktion erstellt.
Beim Erstellen des ersten Datensatzes, warten also 999 weitere Transaktionen darauf, ausgeführt zu werden!
So geht's besser
Bündeln Sie viele kleine schreibende Transaktionen zu 1 Transaktion.
do as transaction
for i in range(1000) do
create Tabelle1;
end
end;
Hier wird die gesamte Schleife innerhalb 1 Transaktion durchgeführt. Das reduziert in unserem Beispiel die Warteschlange auf 0.
Beispiel 2
Es geht aber auch andersrum. Im folgenden Beispiel erhalten alle Kunden aus der Tabelle Kunden eine E-Mail durch ein Skript in einem Trigger nach Änderung.
Streng genommen ergänzen Sie hier die vorangehende schreibende Transaktion (welche den Trigger auslöst) um die Anweisungen aus dem Trigger-Skript.
for kunde in select Kunden do
sendEmail({
from: "support@ninox.com",
to: kunde.'E-Mail-Adresse',
subject: "Newsletter",
text: 'E-Mail-Vorlage'
})
end
Die schreibende Transaktion wird hier unnötigerweise aufgepumpt, sodass der Vorgang länger dauert als nötig.
So geht's besser
Führen Sie nicht schreibende Bestandteile einer großen schreibenden Transaktion in einer separaten Transaktion aus.
do as deferred
for kunde in select Kunden do
sendEmail({
from: "support@ninox.com",
to: kunde.'E-Mail-Adresse',
subject: "Newsletter",
text: 'E-Mail-Vorlage'
})
end
end
Hier wird Ihr Trigger-Skript nicht mehr mit der vorangehenden Transaktion ausgeführt, sondern in einer nachgestellten Transaktion.
Mehr zu do as ...
in Performance der Skripte optimieren.
Warum Sie sparsam mit select
umgehen sollten
Wenn Sie select
verwenden, ist es hilfreich, die gewünschte Auswahl genauer zu definieren.
Sie sollten dabei allerdings select
nie direkt mit Klammern [...]
verwenden.
Beispiel 1
select Kunden[Firmensitz = "Deutschland"]
Hier werden erst alle Kunden ausgewählt, anschließend wird nach Firmensitz gefiltert.
So geht's besser
Ziehen Sie die Filter-Bedingung aus der Klammer
[...]
in dieselect
-Anweisung.
select Kunden where Firmensitz = "Deutschland"
Durch
where
werden von Anfang an nur passende Datensätze ausgewählt.
select
-Anweisungen sind super hilfreich, Sie sollten sie aber grundsätzlich als perfomance-lastig betrachten. Jede select
-Anweisung, die Sie nicht setzen, ist eine gute select
-Anweisung.
Beispiel 2
Sie möchten Kunden aus Deutschland abhängig vom jeweiligen Umsatz in 3 Gruppen einteilen.
let deGross := select Kunden where Firmensitz = "Deutschland" and Umsatz > 10000;
let deMittel := select Kunden where Firmensitz = "Deutschland" and
Umsatz <= 10000 and Umsatz > 5000;
let deKlein := select Kunden where Firmensitz = "Deutschland" and Umsatz <= 5000
Die select
-Anweisungen hier sind einzeln betrachtet völlig in Ordnung, das Skript könnte jedoch insgesamt optimiert werden, da die select
-Anweisungen viel gemeinsam haben.
So geht's besser
Versuchen Sie mit möglichst wenig
select
-Anweisungen auszukommen. Speichern Sie wiederverwendbare Rückgabewerte vonselect
-Anweisungen in Variablen.
let deKunden := select Kunden where Firmensitz = "Deutschland";
let deGross := deKunden[Umsatz > 10000];
let deMittel := deKunden[Umsatz <= 10000 and Umsatz > 5000];
let deKlein := deKunden[Umsatz <= 5000];
Hier wird nur eine
select
-Anweisung verwendet und in einer Variable gespeichert. Diese Variable wird dann verwendet, um die Auswahl zu präzisieren.
Prüfen Sie außerdem, ob es eine Ninox-Funktion gibt, die Sie bei Ihrem Vorhaben unterstützen kann. Insbesondere, wenn Sie dadurch select
-Anweisungen und Schleifen reduzieren können.
Beispiel 3
Sie suchen nach dem niedrigsten Umsatz in der Tabelle Kunden.
let kleinsterUmsatz := Infinity;
for kunde in select Kunden do
if kunde.Umsatz < kleinsterUmsatz then
kleinsterUmsatz := kunde.Umsatz
end
end;
kleinsterUmsatz
Dieses Skript ist viel zu kompliziert für einen so einfachen Anwendungsfall.
So geht's besser
Verwenden Sie die entsprechende Ninox-Funktion, hier:
min()
. Aber es gibt auch andere nützliche Funktionen, wie z.B. max(),sum()
,first()
,count()
, uvm!
min((select Kunden).Umsatz)
Dieses Skript reduziert die 7 Zeilen aus dem vorherigen Skript auf eine und bereitet Ihnen beim Lesen bestimmt weniger Kopfschmerzen.
Antwort
Content aside
- vor 10 MonatenZuletzt aktiv
- 16Ansichten
-
1
Folge bereits