Anwendungsdesign für die Datenbankleistung

Ändern Sie die text -Eigenschaft eines SQLStatement-Objekts nicht, nachdem Sie es ausgeführt haben. Verwenden Sie stattdessen eine SQLStatement-Instanz für jede SQL-Anweisung und Anweisungsparameter, um verschiedene Werte bereitzustellen.

Bevor eine SQL-Anweisung ausgeführt wird, wird sie von der Laufzeitumgebung vorbereitet (kompiliert), um festzustellen, welche Schritte intern ausführt werden müssen, um die Anweisung auszuführen. Wenn Sie SQLStatement.execute() für eine SQLStatement-Instanz aufrufen, die zuvor noch nicht ausgeführt wurde, wird die Anweisung automatisch vorbereitet, bevor sie ausgeführt wird. Bei nachfolgenden Aufrufen der execute() -Methode ist die Anweisung dann bereits vorbereitet, sofern die SQLStatement.text -Eigenschaft nicht geändert wurde. Deshalb wird sie schneller ausgeführt.

Den größten Vorteil erzielen Sie, wenn Sie die Anweisung mit Anweisungsparametern anpassen. So können Anweisungen wiederverwendet werden, selbst wenn sich Werte in der Anweisung ändern. (Anweisungsparameter werden mit der assoziativen Array-Eigenschaft SQLStatement.parameters angegeben.) Anders als beim Ändern der text -Eigenschaft der SQLStatement-Instanz muss die Laufzeitumgebung die Anweisung nicht erneut vorbereiten, wenn Sie die Werte der Anweisungsparameter ändern.

Wenn Sie eine SQLStatement-Instanz wiederverwenden, muss Ihre Anwendung einen Verweis auf die SQLStatement-Instanz speichern, nachdem sie vorbereitet wurde. Deklarieren Sie dazu die Variable als Variable mit Klassenumfang anstatt mit Funktionsumfang. Eine gute Vorgehensweise, die SQLStatement in eine Variable mit Klassenumfang zu ändern, besteht darin, die Anwendung so zu strukturieren, dass eine SQL-Anweisung in eine einzelne Klasse gesetzt wird. Auch eine Gruppe von Anweisungen, die im Zusammenhang ausgeführt werden, lassen sich von einer einzelnen Klasse umhüllen. (Diese Technik wird als „Command Design Pattern“ bezeichnet.) Indem Sie die Instanzen als Mitgliedsvariablen der Klasse definieren, bleiben sie erhalten, solange die Instanz der „umhüllenden“ Klasse in der Anwendung vorhanden ist. Sie können im Mindestfall einfach eine Variable definieren, die die SQLStatement-Instanz außerhalb einer Funktion enthält, sodass die Instanz im Speicher verbleibt. Deklarieren Sie die SQLStatement-Instanz zum Beispiel als Mitgliedsvariable in einer ActionScript-Klasse oder als Nicht-Funktions-Variable in einer JavaScript-Datei. Sie können dann die Werte der Anweisungsparameter festlegen und die execute() -Methode aufrufen, wenn die Abfrage dann ausgeführt werden soll.

Verwenden Sie Datenbankindizes, um die Ausführungsgeschwindigkeit beim Vergleichen und Sortieren von Daten zu erhöhen.

Wenn Sie einen Index für eine Spalte erstellen, speichert die Datenbank eine Kopie der Daten in dieser Spalte. Die Kopie wird in numerisch oder alphabetisch sortierter Reihenfolge gehalten. Durch diese Sortierung kann die Datenbank schnell Werte abgleichen (zum Beispiel bei Verwendung des Gleichheitsoperators) und die Ergebnisdaten mithilfe der ORDER BY -Klausel sortieren.

Datenbankindizes werden fortlaufend auf dem neuesten Stand gehalten. Deshalb dauern Datenänderungen (INSERT oder UPDATE) für diese Tabelle etwas länger. Die Daten können möglicherweise jedoch erheblich schneller abgerufen werden. Wegen dieser Leistungseinschränkung sollten Sie nicht einfach jede Spalte jeder Tabelle mit einem Index versehen. Verwenden Sie stattdessen eine Strategie zur Definition Ihrer Indizes. Orientieren Sie sich an den folgenden Richtlinien, um Ihre Indexierungsstrategie zu planen:

  • Indexieren Sie Spalten, die bei Tabellenzusammenführungen, in WHERE-Klauseln oder in ORDER BY-Klauseln verwendet werden.

  • Wenn Spalten häufig zusammen verwendet werden, indexieren Sie sie mit einem gemeinsamen Index.

  • Für Spalten mit Textdaten, die Sie alphabetisch sortiert abrufen, legen Sie die COLLATE NOCASE-Sortierreihenfolge für den Index fest.

Ziehen Sie das Vorkompilieren von SQL-Anweisungen während Leerlaufzeiten der Anwendung in Betracht.

Wenn eine SQL-Anweisung zum ersten Mal ausgeführt wird, ist dies langsamer, da der SQL-Text von der Datenbankengine vorbereitet (kompiliert) wird. Da die Vorbereitung und Ausführung einer Anweisung ressourcenintensiv sein können, bietet es sich möglicherweise an, die anfänglichen Daten im Voraus zu laden und dann andere Anweisungen im Hintergrund auszuführen:

  1. Laden Sie die Daten, die die Anwendung zuerst benötigt..

  2. Nachdem die ersten Startoperationen der Anwendung abgeschlossen sind oder wenn die Anwendung gerade nicht beschäftigt ist, führen Sie andere Anweisungen aus.

Angenommen, Ihre Anwendung greift zum Beispiel überhaupt nicht auf die Datenbank zu, um den Anfangsbildschirm anzuzeigen. Warten Sie in diesem Fall, bis dieser Bildschirm angezeigt wird, bevor Sie die Datenbankverbindung öffnen. Erstellen Sie dann die SQLStatement-Instanzen und führen Sie so viel Code wie möglich aus.

Es kann aber auch sein, dass Ihre Anwendung beim Starten sofort einige Daten anzeigt, zum Beispiel das Ergebnis einer bestimmten Abfrage. Führen Sie in diesem Fall die SQLStatement-Instanz für diese Abfrage aus. Nachdem die ersten Daten geladen und angezeigt werden, erstellen Sie SQLStatement-Instanzen für anderen Datenbankoperationen und führen Sie nach Möglichkeit andere Anweisungen aus, die später benötigt werden.

In der Praxis ist die zusätzliche Zeit für das Vorbereiten der Anweisung nur einmal erforderlich. Sie hat vermutlich keine großen Auswirkungen auf die Gesamtleistung.

Gruppieren Sie mehrere SQL-Datenänderungsoperationen in einer Transaktion.

Angenommen, Sie führen zahlreiche SQL-Anweisungen aus, die das Hinzufügen oder Ändern von Daten beinhalten ( INSERT - oder UPDATE -Anweisungen). Sie können die Leistung deutlich verbessern, indem Sie alle Anweisungen in einer expliziten Transaktion ausführen. Wenn Sie eine Transaktion nicht explizit beginnen, wird jede Anweisung in ihrer eigenen automatisch erstellten Transaktion ausgeführt. Nachdem jede Transaktion (Anweisung) abgeschlossen ist, schreibt die Laufzeitumgebung die resultierenden Daten in die Datenbankdatei auf der Festplatte.

Überlegen Sie, was passiert, wenn Sie dagegen explizit eine Transaktion erstellen und die Anweisungen im Kontext der Transaktion ausführen. Die Laufzeitumgebung nimmt alle Änderungen im Speicher vor und schreibt dann alle Änderungen an der Datenbankdatei zur gleichen Zeit, wenn die Transaktion ausgeführt wird. Das Schreiben der Daten auf die Festplatte ist normalerweise der zeitaufwändigste Teil der Operation. Dementsprechend können Sie die Leistung erheblich verbessern, wenn es nur einen Schreibvorgang gibt anstatt einen pro SQL-Anweisung.

Verarbeiten Sie große SELECT -Abfrageergebnisse in Portionen, indem Sie die execute() -Methode (mit dem prefetch -Parameter) und die next() -Methode der SQLStatement-Klasse verwenden.

Angenommen, Sie führen eine AQL-Anweisung aus, die einen großen Ergebnissatz abruft. Die Anwendung verarbeitet dann jede Datenzeile in einer Schleife. Zum Beispiel formatiert sie die Daten oder erstellt Objekte daraus. Das Verarbeiten der Daten kann viel Zeit in Anspruch nehmen, was zu Renderingproblemen wie einem nicht reagierenden Bildschirm führen kann. Wie unter Asynchrone Operationen beschrieben, besteht eine Lösung darin, die Arbeit in Abschnitte aufzuteilen. Mit der SQL-Datenbank-API ist die Aufteilung der Datenverarbeitung ein einfacher Vorgang.

Die execute() -Methode der SQLStatement-Klasse hat einen optionalen prefetch -Parameter (dies ist der erste Parameter). Wenn Sie einen Wert dafür angeben, legt dieser die maximale Anzahl von Ergebniszeilen fest, die die Datenbank zurückgibt, wenn die Ausführung abgeschlossen ist:

dbStatement.addEventListener(SQLEvent.RESULT, resultHandler); 
dbStatement.execute(100); // 100 rows maximum returned in the first set

Nachdem der erste Satz von Ergebnisdaten zurückgegeben wurde, können Sie die next() -Methode aufrufen, um die Ausführung der Anweisung fortzusetzen und einen weiteren Satz mit Ergebniszeilen abzurufen. Wie die execute() -Methode akzeptiert auch die next() -Methode einen prefetch -Parameter, um die maximale Anzahl der zurückzugebenden Ergebniszeilen festzulegen:

// This method is called when the execute() or next() method completes 
function resultHandler(event:SQLEvent):void 
{ 
    var result:SQLResult = dbStatement.getResult(); 
    if (result != null) 
    { 
        var numRows:int = result.data.length; 
        for (var i:int = 0; i < numRows; i++) 
        { 
            // Process the result data 
        } 
         
        if (!result.complete) 
        { 
            dbStatement.next(100); 
        } 
    } 
}

Sie können die next() -Methode wiederholt aufrufen, bis alle Daten geladen wurden. Wie im vorherigen Beispiel gezeigt, können Sie bestimmen, wann alle Daten geladen wurden. Überprüfen Sie die complete -Eigenschaft des SQLResult-Objekts, das jedes Mal erstellt wird, wenn die execute() - oder next() -Methode abgeschlossen ist.

Hinweis: Verwenden Sie den prefetch -Parameter und die next() -Methode, um die Verarbeitung der Ergebnisdaten aufzuteilen. Verwenden Sie diesen Parameter und diese Methode nicht, um die Ergebnisse einer Abfrage auf einen Teil der Ergebnismenge einzuschränken. Wenn Sie nur eine Untermenge der Zeilen in der Ergebnismenge einer Anweisung abrufen möchten, verwenden Sie die LIMIT -Klausel der SELECT -Anweisung. Bei einem großen Ergebnissatz können Sie immer noch den prefetch -Parameter und die next() -Methode verwenden, um die Verarbeitung der Ergebnisse aufzuteilen.
Verwenden Sie ggf. mehrere asynchrone SQLConnection-Objekte mit einer einzelnen Datenbank, um mehrere Anweisungen gleichzeitig auszuführen.

Wenn ein SQLConnection-Objekt mithilfe der openAsync() -Methode mit einer Datenbank verbunden ist, wird sie im Hintergrund ausgeführt anstatt im Hauptausführungs-Thread der Laufzeitumgebung. Des Weiteren wird jede SQLConnection in ihrem eigenen Hintergrund-Thread ausgeführt. Durch Verwendung mehrerer SQLConnection-Objekte können Sie effektiv mehrere SQL-Anweisungen gleichzeitig ausführen.

Dieser Ansatz hat jedoch auch potenzielle Nachteile. Der wichtigste ist, dass jedes zusätzliche SQLStatement-Objekt zusätzlichen Arbeitsspeicher benötigt. Außerdem bedeutet die gleichzeitige Ausführung auch Mehrarbeit für den Prozessor, besonders bei Computern mit nur einer CPU oder einem CPU-Kern. Aufgrund dieser Nachteile wird dieser Ansatz für mobile Geräte nicht empfohlen.

Ein weiterer Nachteil ist, dass der potenzielle Vorteil aus der Wiederverwendung von SQLStatement-Objekten verloren geht, wenn ein SQLStatement-Objekt mit einem einzelnen SQLConnection-Objekt verknüpft ist. Deshalb kann das SQLStatement-Objekt nicht wiederverwendet werden, wenn es einem bereits verwendeten SQLConnection-Objekt zugewiesen ist.

Wenn Sie mehrere SQLConnection-Objekte verwenden, die mit einer einzelnen Datenbank verbunden sind, denken Sie daran, dass jedes Objekt seine Anweisung in einer eigenen Transaktion ausführt. Berücksichtigen Sie diese separaten Transaktionen in jedem Code, der Daten ändert (beispielsweise durch Hinzufügen, Ändern oder Löschen).

Paul Robertson hat eine Open-Source-Codebibliothek erstellt, die Sie beim Integrieren der Vorteile der Verwendung von mehreren SQLConnection-Objekten unterstützt, während die möglichen Nachteile minimiert werden. Die Bibliothek verwendet einen Pool von SQLConnection-Objekten und verwaltet die damit verknüpften SQLStatement-Objekte. Auf diese Weise wird sichergestellt, dass SQLStatement-Objekte wiederverwendet werden und mehrere SQLConnection-Objekte verfügbar sind, um mehrere Anweisungen gleichzeitig auszuführen. Wenn Sie weitere Informationen wünschen oder die Bibliothek herunterladen möchten, besuchen Sie http://probertson.com/projects/air-sqlite/ .