Nachdem ich den folgenden Artikel gelesen hatte, stellte ich fest, dass der Test des Autors für Freunde, die ASP verwenden, wirklich hilfreich ist. Er sollte nicht nur für ASP, sondern auch für andere Sprachen ähnlich sein. Das Generieren dynamischer Inhalte auf dem Server ist einer der Hauptgründe für die Verwendung von ASP. Daher bestand das erste Testprojekt, das wir ausgewählt haben, darin, die beste Methode zum Senden dynamischer Inhalte an den Antwortstream zu ermitteln. Es gibt zwei grundlegende Optionen (und einige Variationen davon): die Verwendung von Inline-ASP-Tags und die Verwendung der Response.Write-Anweisung.
Um diese verschiedenen Ansätze zu testen, haben wir eine einfache ASP-Seite erstellt, die einige Variablen definiert und sie dann in eine Tabelle eingefügt hat. Obwohl diese Seite einfach und ohne praktischen Nutzen ist, reicht sie aus, um einzelne Probleme zu isolieren und zu testen.
2.1 Verwendung von ASP-Inline-Tags
Der erste Test besteht darin, das Inline-Tag <%= x %> von ASP zu verwenden, wobei x eine Variable ist. Dies ist die bequemste Methode und erleichtert das Lesen und Verwalten des HTML-Teils der Seite.
Kopieren Sie den Codecode wie folgt:
<% OPTION EXPLICIT
Vorname abdunkeln
DimLastName
Dim MiddleInitial
Dunkle Adresse
Dunkle Stadt
Schwacher Zustand
DimPhoneNumber
Faxnummer dimmen
E-Mail abdunkeln
DimBirthDate
Vorname = John
MiddleInitial = Q
Nachname = Öffentlich
Adresse = 100 Main Street
Stadt=New York
Bundesstaat=NY
Telefonnummer = 1-212-555-1234
Faxnummer = 1-212-555-1234
E-Mail = [email protected]
Geburtsdatum = 1.1.1950
%>
<HTML>
<KOPF>
<TITLE>Antworttest</TITLE>
</HEAD>
<KÖRPER>
<H1>Antworttest</H1>
<TABELLE>
<tr><td><b>Vorname:</b></td><td><%= Vorname %></td></tr>
<tr><td><b>Middle Initial:</b></td><td><%= MiddleInitial %></td></tr>
<tr><td><b>Nachname:</b></td><td><%= Nachname %></td></tr>
<tr><td><b>Adresse:</b></td><td><%= Adresse %></td></tr>
<tr><td><b>Stadt:</b></td><td><%= Stadt %></td></tr>
<tr><td><b>Staat:</b></td><td><%= Staat %></td></tr>
<tr><td><b>Telefonnummer:</b></td><td><%= Telefonnummer %></td></tr>
<tr><td><b>Faxnummer:</b></td><td><%= FaxNumber %></td></tr>
<tr><td><b>E-Mail:</b></td><td><%= E-Mail %></td></tr>
<tr><td><b>Geburtsdatum:</b></td><td><%= Geburtsdatum %></td></tr>
</TABLE>
</BODY>
</HTML>
Der vollständige Code von /app1/response1.asp
Bester Rekord = 8,28 ms/Seite
2.2 Verwenden Sie Response.Write, um jede Zeile HTML-Code auszugeben
Es gibt eine Menge guter Literatur, die besagt, dass der vorhergehende Inline-Markup-Ansatz vermieden werden sollte, da er zu einem Vorgang führt, der als Kontextwechsel bezeichnet wird. Dieser Vorgang findet statt, wenn sich die Art des vom Webserver verarbeiteten Codes ändert (vom Senden von reinem HTML zur Skriptverarbeitung oder umgekehrt), und dieser Wechsel dauert eine gewisse Zeit. Nachdem viele Programmierer dies gelernt haben, besteht ihre erste Reaktion darin, die Response.Write-Funktion zu verwenden, um jede Zeile HTML-Code auszugeben:
Kopieren Sie den Codecode wie folgt:
...
Response.Write(<html>)
Response.Write(<head>)
Response.Write( <title>Antworttest</title>)
Response.Write(</head>)
Response.Write(<body>)
Response.Write(<h1>Antworttest</h1>)
Response.Write(<Tabelle>)
Response.Write(<tr><td><b>Vorname:</b></td><td> & Vorname & </td></tr>)
Response.Write(<tr><td><b>Middle Initial:</b></td><td> & MiddleInitial & </td></tr>)
...
/app1/response2.asp-Fragment
Bester Rekord = 8,28 ms/Seite
Reaktionszeit = 8,08 ms/Seite
Differenz = -0,20 ms (2,4 % Reduzierung)
Die Leistungsverbesserung, die wir im Vergleich zur Inline-Markup-Version sahen, war so gering, dass es einfach überraschend war. Dies kann daran liegen, dass die Seite viel mehr Funktionsaufrufe enthält. Diese Methode hat jedoch einen größeren Nachteil. Da der HTML-Code in die Funktion eingebettet ist, wird der Skriptcode sehr langwierig und unpraktisch zu lesen und zu warten.
2.3 Wrapper-Funktionen verwenden
Response.Write fügt am Ende der Textzeile kein CRLF (Carriage Return - Line Feed, Carriage Return - Line Feed) hinzu, was der enttäuschendste Aspekt bei der Verwendung der oben genannten Methode ist. Obwohl der HTML-Code auf der Serverseite gut formatiert wurde, sehen Sie im Browser immer noch nur eine lange Codezeile. Aber dieses Problem war nicht die einzige Enttäuschung. Die Leute stellten bald fest, dass es keine Response.WriteLn-Funktion gab, die CRLF automatisch hinzufügen konnte. Eine natürliche Reaktion besteht darin, eine Wrapper-Funktion für Response.Write zu erstellen und nach jeder Zeile CRLF hinzuzufügen:
...
writeCR(<tr><td><b>Vorname:</b></td><td> & Vorname & </td></tr>)
...
SUB writeCR(str)
Response.Write(str & vbCRLF)
ENDE SUB
/app1/response4.asp-Fragment
Bester Rekord = 8,08 ms/Seite
Reaktionszeit = 10,11 ms/Seite
Differenz = +2,03 ms (25,1 % Anstieg)
Die Folge ist ein erheblicher Leistungsabfall. Dies liegt natürlich hauptsächlich daran, dass diese Methode die Anzahl der Funktionsaufrufe verdoppelt und ihre Auswirkungen auf die Leistung sehr offensichtlich sind. Diese Verwendung sollte unbedingt vermieden werden, da CRLF zu zwei zusätzlichen Bytes am Ende jeder Zeile führt und diese beiden Bytes für den Browser nutzlos sind, um die Seite anzuzeigen. In den meisten Fällen erleichtert das schöne Format des browserseitigen HTML-Codes Ihren Konkurrenten lediglich das Lesen und Verstehen des Seitendesigns.
2.4 Mehrere Response.Write zusammenführen
Wenn man den letzten Test zur Kapselung von Funktionen außer Acht lässt, wäre der nächste logische Schritt, alle Zeichenfolgen aus separaten Response.Write-Anweisungen in einer Anweisung zusammenzuführen, wodurch die Anzahl der Funktionsaufrufe verringert und die Effizienz des Codes verbessert wird.
Kopieren Sie den Codecode wie folgt:
Response.Write(<html> & _
<Kopf> & _
<title>Antworttest</title> & _
</head> & _
<Körper> & _
<h1>Antworttest</h1> & _
<Tabelle> & _
<tr><td><b>Vorname:</b></td><td> & Vorname & </td></tr> & _
...
<tr><td><b>Geburtsdatum:</b></td><td> & Geburtsdatum & </td></tr> & _
</table> & _
</body> & _
</html>)
/app1/response3.asp-Fragment
Bester Rekord = 8,08 ms/Seite
Reaktionszeit = 7,05 ms/Seite
Differenz = -1,03 ms (12,7 % Reduzierung)
Dies ist bei weitem die beste Methode.
2.5 Kombinieren Sie mehrere Antworten. Schreiben Sie CRLF und fügen Sie es am Ende jeder Zeile hinzu
Einige Leute sind auch sehr besorgt darüber, ob ihr HTML-Code auf der Browserseite schön aussieht, deshalb fügen wir am Ende jeder HTML-Codezeile einen Wagenrücklauf ein, indem wir die vbCRLF-Konstante verwenden. Die anderen Testcodes sind die gleichen wie im obigen Beispiel .
...
Response.Write(<html> & vbCRLF & _
<head> & vbCRLF & _
<title>Antworttest</title> & vbCRLF & _
</head> & vbCRLF & _
...
/app1/response5.asp-Fragment
Bester Rekord = 7,05 ms/Seite
Reaktionszeit = 7,63 ms/Seite
Differenz = +0,58 ms (8,5 % Anstieg)
Das Ergebnis ist ein leichter Leistungsabfall, der wahrscheinlich auf die Hinzufügung von String-Verkettungsoperationen und die Zunahme des Ausgabetexts zurückzuführen ist.
2.6 Kommentare
Basierend auf den Ergebnissen des obigen ASP-Ausgabetests kommen wir zu den folgenden Kodierungsregeln:
Vermeiden Sie die übermäßige Verwendung von eingebettetem ASP.
Kombinieren Sie so viele Response.Write-Anweisungen wie möglich in einer einzigen Anweisung.
Kapseln Sie Response.Write niemals nur, um CRLF hinzuzufügen.
Wenn Sie die HTML-Ausgabe formatieren möchten, fügen Sie CRLF direkt nach der Response.Write-Anweisung hinzu.
Gliederung: Was ist die effizienteste Möglichkeit, von ASP dynamisch generierte Inhalte auszugeben? Was ist der beste Weg, ein Datenbank-Recordset zu extrahieren? Dieser Artikel testet fast 20 häufige Probleme bei der ASP-Entwicklung. Die vom Testtool angezeigte Zeit zeigt uns: Diese Probleme, die normalerweise als selbstverständlich angesehen werden, verdienen nicht nur Aufmerksamkeit, sondern bergen auch unerwartete Geheimnisse.
1. Testzweck
Der erste Teil dieses Artikels untersucht einige grundlegende Probleme bei der ASP-Entwicklung und liefert einige Leistungstestergebnisse, um den Lesern zu helfen, zu verstehen, welche Auswirkungen der auf der Seite platzierte Code auf die Leistung hat. ADO ist eine universelle, benutzerfreundliche Datenbankschnittstelle, die von Microsoft entwickelt wurde. Es stellt sich heraus, dass die Interaktion mit der Datenbank über ADO eine der wichtigsten Anwendungen von ASP ist. Im zweiten Teil werden wir dieses Problem untersuchen.
Die von ADO bereitgestellte Funktionalität ist recht umfangreich, daher besteht die größte Schwierigkeit bei der Vorbereitung dieses Artikels darin, den Umfang des Problems zu definieren. Angesichts der Tatsache, dass das Extrahieren großer Datenmengen die Belastung des Webservers erheblich erhöhen kann, haben wir beschlossen, dass der Hauptzweck dieses Abschnitts darin besteht, herauszufinden, welche Konfiguration für den Betrieb von ADO-Recordsets optimal ist. Doch auch nach der Eingrenzung des Problemumfangs stehen wir immer noch vor großen Schwierigkeiten, da ADO viele verschiedene Möglichkeiten haben kann, dieselbe Aufgabe zu erledigen. Beispielsweise können Recordsets nicht nur über die Recordset-Klasse, sondern auch über die Connection- und Command-Klassen extrahiert werden. Selbst nach dem Abrufen des Recordset-Objekts gibt es viele Operationsmethoden, die sich erheblich auf die Leistung auswirken können. Allerdings werden wir, wie im ersten Teil, versuchen, ein möglichst breites Themenspektrum abzudecken.
Das Ziel dieses Abschnitts besteht insbesondere darin, genügend Informationen zu sammeln, um die folgenden Fragen zu beantworten:
Sollte ADOVBS.inc über include referenziert werden?
lSoll ich bei der Verwendung von Recordsets ein separates Verbindungsobjekt erstellen?
lWas ist der beste Weg, ein Recordset zu extrahieren?
lWelcher Cursortyp und welche Datensatzsperrmethode sind am effizientesten?
lSoll ich ein lokales Recordset verwenden?
lWas ist der beste Weg, um Recordset-Eigenschaften festzulegen?
lWelche Methode ist für die Referenzierung von Feldwerten in einem Datensatz am effizientesten?
lIst es eine gute Möglichkeit, die Ausgabe mit einer temporären Zeichenfolge zu sammeln?
2. Testumgebung
In diesem Test wurden insgesamt 21 ASP-Dateien verwendet, die am Ende dieses Artikels heruntergeladen werden können. Jede Seite ist für die Ausführung von drei verschiedenen Abfragen eingerichtet, die jeweils 0, 25 und 250 Datensätze zurückgeben. Dadurch können wir den Initialisierungs- und Ausführungsaufwand der Seite selbst vom Aufwand für das Durchlaufen des Recordsets isolieren.
Um das Testen zu erleichtern, werden die Datenbankverbindungszeichenfolge und die SQL-Befehlszeichenfolge als Anwendungsvariablen in Global.asa gespeichert. Da es sich bei unserer Testdatenbank um SQL Server 7.0 handelt, gibt die Verbindungszeichenfolge OLEDB als Verbindungsanbieter an und die Testdaten stammen aus der Northwind-Datenbank von SQL Server. Der SQL SELECT-Befehl extrahiert 7 angegebene Felder aus der NorthWind Orders-Tabelle.
Kopieren Sie den Codecode wie folgt:
<SCRIPT LANGUAGE=VBScript RUNAT=Server>
Sub Application_OnStart
Application(Conn) = Provider=SQLOLEDB;
Server=MeinServer;
uid=sa;
pwd=;
DATENBANK=Nordwind
Application(SQL) = SELECTTOP 0OrderID, & _
KundenID, & _
Mitarbeiter-ID, & _
Bestelldatum, & _
Erforderliches Datum, & _
Versanddatum, & _
Fracht & _
VON[Bestellungen]
Sub beenden
</SCRIPT>
'Alternative SQL – 25 Datensätze
Application(SQL) = SELECTTOP 25OrderID, & _
KundenID, & _
Mitarbeiter-ID, & _
Bestelldatum, & _
Erforderliches Datum, & _
Versanddatum, & _
Fracht & _
VON[Bestellungen]
'Alternative SQL-250-Datensätze
Application(SQL) = SELECTTOP 250 OrderID, & _
KundenID, & _
Mitarbeiter-ID, & _
Bestelldatum, & _
Erforderliches Datum, & _
Versanddatum, & _
Fracht & _
VON[Bestellungen]
Die Testserverkonfiguration war wie folgt: 450 MHz Pentium, 512 MB RAM, NT Server 4.0 SP5, MDAC 2.1 (Data Access Component) und Microsoft Scripting Engine Version 5.0. SQL Server wird auf einem anderen Computer mit einer ähnlichen Konfiguration ausgeführt. Wie im ersten Teil verwenden wir weiterhin das Microsoft Web Application Stress Tool, um die Zeit von der ersten Seitenanforderung bis zum letzten vom Server empfangenen Byte (TTLB, Time To Last Byte) aufzuzeichnen, die Zeit wird in Millisekunden angegeben. Das Testskript rief jede Seite mehr als 1300 Mal auf und die Ausführung dauerte etwa 20 Stunden. Die unten angegebenen Zeiten sind die durchschnittlichen TTLB für die Sitzung. Denken Sie daran, dass es uns wie im ersten Teil nur um die Effizienz des Codes geht, nicht um seine Skalierbarkeit oder Serverleistung.
Beachten Sie außerdem, dass wir die Serverpufferung aktiviert haben. Um allen Dateinamen die gleiche Länge zu geben, sind in einigen Dateinamen außerdem ein oder mehrere Unterstriche eingebettet.
3. Erster Test
Im ersten Test haben wir ein Recordset extrahiert, das ein typisches Szenario simuliert, das in den Microsoft ASP ADO-Beispielen zu finden ist. In diesem Beispiel (ADO__01.asp) öffnen wir zunächst eine Verbindung und erstellen dann das Recordset-Objekt. Natürlich ist das Skript hier gemäß den im ersten Teil dieses Artikels zusammengefassten Codierungsregeln optimiert.
Kopieren Sie den Codecode wie folgt:
<% Option Explicit %>
<!-- #Include file=ADOVBS.INC -->
<%
Dim objConn
Dim objRS
Response.Write(_
<HTML><HEAD> & _
<TITLE>ADO-Test</TITLE> & _
</HEAD><BODY> _
)
Set objConn = Server.CreateObject(ADODB.Connection)
objConn.Open Application(Conn)
Setze objRS = Server.CreateObject(ADODB.Recordset)
objRS.ActiveConnection = objConn
objRS.CursorType = adOpenForwardOnly
objRS.LockType = adLockReadOnly
objRS.Open Application(SQL)
Wenn objRS.EOF Dann
Response.Write (Keine Datensätze gefunden)
Anders
'Überschriften schreiben
Response.Write(_
<TABLE BORDER=1> & _
<TR> & _
<TH>BestellID</TH> & _
<TH>Kunden-ID</TH> & _
<TH>Mitarbeiter-ID</TH> & _
<TH>Bestelldatum</TH> & _
<TH>Erforderliches Datum</TH> & _
<TH>Versanddatum</TH> & _
<TH>Fracht</TH> & _
</TR> _
)
'Daten schreiben
Do While Not objRS.EOF
Response.Write(_
<TR> & _
<TD> & objRS(OrderID) & </TD> & _
<TD> & objRS(CustomerID) & </TD> & _
<TD> & objRS(EmployeeID) & </TD> & _
<TD> & objRS(OrderDate) & </TD> & _
<TD> & objRS(RequiredDate) & </TD> & _
<TD> & objRS(ShippedDate) & </TD> & _
<TD> & objRS(Fracht) & </TD> & _
</TR> _
)
objRS.MoveNext
Schleife
Response.Write(</TABLE>)
Ende wenn
objRS.Schließen
objConn.Close
Setze objRS = Nichts
Setze objConn = Nothing
Response.Write(</BODY></HTML>)
%>
Hier sind die Testergebnisse:
Werfen wir einen Blick auf die Bedeutung der Zahlen in jeder Spalte:
0 gibt den TTLB (in Millisekunden) zurück, der für eine Seite mit 0 Datensätzen erforderlich ist. In allen Tests wird dieser Wert als Zeitaufwand für die Generierung der Seite selbst (einschließlich der Erstellung von Objekten) betrachtet, ohne die Zeit für die Iteration durch die Recordset-Daten.
25 TTLB in Millisekunden zum Abrufen und Anzeigen von 25 Datensätzen
Der TTLB in der Spalte „Gesamtzeit/2525“ wird durch 25 geteilt, was dem gesamten durchschnittlichen Zeitaufwand pro Datensatz entspricht.
Disp-Zeit/2525 Spalten-TTLB minus 0 Spalten-TTLB, dann durch 25 dividieren. Dieser Wert spiegelt die Zeit wider, die erforderlich ist, um einen einzelnen Datensatz anzuzeigen, während das Recordset durchlaufen wird.
250 Extrahiert und zeigt TTLB von 250 Datensätzen an.
Der TTLB in der Spalte Gesamtzeit/250250 wird durch 25 geteilt. Dieser Wert stellt den gesamten durchschnittlichen Zeitaufwand eines einzelnen Datensatzes dar.
disp time/250 Der TTLB in Spalte 250 wird vom TTLB in Spalte 0 subtrahiert und dann durch 250 dividiert. Dieser Wert spiegelt die Zeit wider, die erforderlich ist, um einen einzelnen Datensatz anzuzeigen, während das Recordset durchlaufen wird.
Die oben genannten Testergebnisse werden zum Vergleich mit den nächsten Testergebnissen verwendet.
4. Sollte ADOVBS.inc durch Einbindung referenziert werden?
ADOVBS.inc von Microsoft enthält 270 Codezeilen, die die meisten ADO-Eigenschaftskonstanten definieren. Unser Beispiel verweist nur auf zwei Konstanten von ADOVBS.inc. Daher haben wir in diesem Test (ADO__02.asp) die enthaltene Dateireferenz gelöscht und beim Festlegen der Eigenschaften direkt den entsprechenden Wert verwendet.
objRS.CursorType = 0?' adOpenForwardOnly
objRS.LockType = 1' adLockReadOnly
Sie können sehen, dass der Seitenaufwand um 23 % gesunken ist. Dieser Wert hat keinen Einfluss auf die Abruf- und Anzeigezeit einzelner Datensätze, da Änderungen hier keine Auswirkungen auf Recordset-Vorgänge innerhalb der Schleife haben. Es gibt mehrere Möglichkeiten, ADOVBS.inc-Referenzprobleme zu beheben. Wir empfehlen, die Datei ADOVBS.inc als Referenz zu verwenden und die Einstellungen durch Kommentare zu erläutern. Denken Sie daran, wie in Teil 1 erwähnt, dass eine moderate Verwendung von Kommentaren nur minimale Auswirkungen auf die Effizienz Ihres Codes hat. Eine andere Methode besteht darin, die benötigten Konstanten aus der Datei ADOVBS.inc in die Seite zu kopieren.
Es gibt auch eine gute Möglichkeit, dieses Problem zu lösen, indem alle ADO-Konstanten durch eine Verknüpfung mit der ADO-Typbibliothek direkt verfügbar gemacht werden. Fügen Sie der Datei Global.asa den folgenden Code hinzu, um direkt auf alle ADO-Konstanten zuzugreifen:
<!--METADATA TYPE=typelib
FILE=C:ProgrammeGemeinsame DateienSYSTEMADOmsado15.dll
NAME=ADODB-Typbibliothek ->
oder:
<!--METADATA TYPE=typelib
UUID=00000205-0000-0010-8000-00AA006D2EA4
NAME=ADODB-Typbibliothek ->
Daher lautet unsere erste Regel:
lVermeiden Sie es, die Datei ADOVBS.inc einzubeziehen und auf ADO-Konstanten über andere Methoden zuzugreifen und diese zu verwenden.
5. Sollte ich bei Verwendung eines Recordsets ein separates Verbindungsobjekt erstellen?
Um diese Frage richtig zu beantworten, müssen wir den Test unter zwei verschiedenen Bedingungen analysieren: Erstens verfügt die Seite nur über eine Datenbanktransaktion. Zweitens verfügt die Seite über mehrere Datenbanktransaktionen.
Im vorherigen Beispiel haben wir ein separates Connection-Objekt erstellt und es der ActiveConnection-Eigenschaft des Recordset zugewiesen. Wie in ADO__03.asp gezeigt, können wir die Verbindungszeichenfolge jedoch auch direkt der ActiveConnection-Eigenschaft zuweisen, wodurch der zusätzliche Schritt der Initialisierung und Konfiguration des Connection-Objekts im Skript entfällt.
objRS.ActiveConnection = Anwendung(Conn)
Obwohl das Recordset-Objekt noch eine Verbindung herstellen muss, erfolgt die Erstellung zu diesem Zeitpunkt unter hochoptimierten Bedingungen. Dadurch sank der Seitenaufwand um weitere 23 % im Vergleich zum vorherigen Test, und die Anzeigezeit eines einzelnen Datensatzes änderte sich erwartungsgemäß nicht wesentlich.
Daher lautet unsere zweite Regel wie folgt:
lWenn Sie nur ein Recordset verwenden, weisen Sie die Verbindungszeichenfolge direkt der ActiveConnection-Eigenschaft zu.
Als nächstes prüfen wir, ob die oben genannten Regeln noch gültig sind, wenn die Seite mehrere Datensätze verwendet. Um diese Situation zu testen, führen wir eine FOR-Schleife ein, um das vorherige Beispiel zehnmal zu wiederholen. In diesem Test werden wir drei Varianten betrachten:
Zunächst wird, wie in ADO__04.asp gezeigt, das Connection-Objekt in jeder Schleife erstellt und zerstört:
Kopieren Sie den Codecode wie folgt:
Dim ich
Für i = 1 bis 10
Set objConn = Server.CreateObject(ADODB.Connection)
objConn.Open Application(Conn)
Setze objRS = Server.CreateObject(ADODB.Recordset)
objRS.ActiveConnection = objConn
objRS.CursorType = 0 'adOpenForwardOnly
objRS.LockType = 1 'adLockReadOnly
objRS.Open Application(SQL)
Wenn objRS.EOF Dann
Response.Write (Keine Datensätze gefunden)
Anders
'Überschriften schreiben
...
'Daten schreiben
...
Ende wenn
objRS.Schließen
Setze objRS = Nichts
objConn.Close
Setze objConn = Nothing
Nächste
Zweitens erstellen Sie, wie in ADO__05.asp gezeigt, ein Verbindungsobjekt außerhalb der Schleife und geben dieses Objekt für alle Recordsets frei:
Kopieren Sie den Codecode wie folgt:
Set objConn = Server.CreateObject(ADODB.Connection)
objConn.Open Application(Conn)
Dim ich
Für i = 1 bis 10
Setze objRS = Server.CreateObject(ADODB.Recordset)
objRS.ActiveConnection = objConn
objRS.CursorType = 0 'adOpenForwardOnly
objRS.LockType = 1 'adLockReadOnly
objRS.Open Application(SQL)
Wenn objRS.EOF Dann
Response.Write (Keine Datensätze gefunden)
Anders
'Überschriften schreiben
...
'Daten schreiben
...
Ende wenn
objRS.Schließen
Setze objRS = Nichts
Nächste
objConn.Close
Setze objConn = Nothing
Drittens weisen Sie, wie in ADO__06.asp gezeigt, in jeder Schleife die Verbindungszeichenfolge der ActiveConnection-Eigenschaft zu:
Kopieren Sie den Codecode wie folgt:
Dim ich
Für i = 1 bis 10
Setze objRS = Server.CreateObject(ADODB.Recordset)
objRS.ActiveConnection = Anwendung(Conn)
objRS.CursorType = 0 'adOpenForwardOnly
objRS.LockType = 1 'adLockReadOnly
objRS.Open Application(SQL)
Wenn objRS.EOF Dann
Response.Write (Keine Datensätze gefunden)
Anders
'Überschriften schreiben
...
'Daten schreiben
...
Ende wenn
objRS.Schließen
Setze objRS = Nichts
Nächste
Wie wir vermuten können, ist das Erstellen und Entfernen von Verbindungsobjekten innerhalb einer Schleife die am wenigsten effiziente Methode. Überraschenderweise ist die direkte Zuweisung der Verbindungszeichenfolge zur ActiveConnection-Eigenschaft innerhalb der Schleife jedoch nur geringfügig langsamer als die gemeinsame Nutzung eines einzelnen Connection-Objekts.
Dennoch sollte die dritte Regel lauten:
lWenn mehrere Datensatzsätze auf derselben Seite verwendet werden, erstellen Sie ein einzelnes Verbindungsobjekt und geben Sie es über die ActiveConnection-Eigenschaft frei.
6. Welcher Cursortyp und welche Datensatzsperrmethode sind am effizientesten?
In allen Tests haben wir bisher nur Vorwärtscursor verwendet, um auf das Recordset zuzugreifen. Es gibt drei Arten von Cursorn, die von ADO für Datensatzsätze bereitgestellt werden: statische scrollbare Cursor, dynamische scrollbare Cursor und Tastensatz-Cursor. Jeder Cursor bietet unterschiedliche Funktionen, z. B. den Zugriff auf den vorherigen und den nächsten Datensatz, ob Sie Änderungen an Daten durch andere Programme sehen können usw. Eine detaillierte Diskussion der Funktionen der einzelnen Cursortypen würde jedoch den Rahmen dieses Artikels sprengen. Die folgende Tabelle ist eine vergleichende Analyse verschiedener Cursortypen.
Alle anderen Cursortypen erfordern im Vergleich zu Nur-Vorwärts-Cursorern zusätzlichen Overhead und diese Cursor sind innerhalb von Schleifen im Allgemeinen langsamer. Deshalb möchten wir Ihnen den folgenden Vorbehalt mitteilen: Denken Sie niemals so – nun ja, manchmal verwende ich dynamische Cursor, also werde ich immer diesen Cursor verwenden.
Die gleiche Meinung gilt für die Wahl der Methode zum Sperren von Datensätzen. Im vorherigen Test wurde nur die schreibgeschützte Sperrmethode verwendet, es gibt jedoch drei weitere Methoden: konservative, offene und offene Stapelverarbeitung. Wie Cursortypen bieten diese Sperrmethoden unterschiedliche Funktionen und Kontrolle über die Arbeit mit Recordset-Daten.
Wir kommen zu folgenden Regeln:
lVerwenden Sie den einfachsten Cursortyp und die einfachste Datensatzsperrmethode, die für die Aufgabe geeignet sind.
7. Welche Methode eignet sich am besten zum Extrahieren eines Datensatzes?
Bisher haben wir Recordsets durch die Erstellung von Recordset-Objekten extrahiert, ADO bietet jedoch auch indirekte Methoden zum Extrahieren von Recordsets. Der folgende Test vergleicht ADO__03.asp und das Erstellen eines Recordsets direkt aus dem Connection-Objekt (CONN_01.asp):
Kopieren Sie den Codecode wie folgt:
Set objConn = Server.CreateObject(ADODB.Connection)
objConn.Open Application(Conn)
Setze objRS = objConn.Execute(Application(SQL))
Sie können sehen, dass sich der Seitenaufwand leicht erhöht hat und sich die Anzeigezeit eines einzelnen Datensatzes nicht geändert hat.
Werfen wir einen Blick auf die Erstellung eines Recordset-Objekts (CMD__02.asp) direkt aus dem Command-Objekt:
Kopieren Sie den Codecode wie folgt:
Set objCmd = Server.CreateObject(ADODB.Command)
objCmd.ActiveConnection = Anwendung(Conn)
objCmd.CommandText = Anwendung (SQL)
Setze objRS = objCmd.Execute
Ebenso erhöht sich der Seitenaufwand leicht, ohne dass sich die Anzeigezeit eines einzelnen Datensatzes wesentlich ändert. Der Leistungsunterschied zwischen den beiden letztgenannten Methoden ist gering, wir müssen jedoch ein wichtiges Problem berücksichtigen.
Beim Erstellen eines Recordsets über die Recordset-Klasse können wir die Verarbeitung des Recordsets mit größter Flexibilität steuern. Da die beiden letztgenannten Methoden keine überwältigende Leistung erzielen, berücksichtigen wir hauptsächlich den standardmäßig zurückgegebenen Cursortyp und die Datensatzsperrmethode. In einigen Fällen ist der Standardwert nicht unbedingt der idealste.
Sofern keine besonderen Gründe für die Wahl zwischen den beiden letztgenannten Methoden vorliegen, empfehlen wir daher, die folgenden Regeln zu berücksichtigen:
l Instanziieren Sie das Recordset über die ADODB.Recordset-Klasse, um die beste Leistung und Flexibilität zu erzielen.
8. Sollte ich ein lokales Recordset verwenden?
ADO ermöglicht die Verwendung lokaler (Client-)Datensätze. Zu diesem Zeitpunkt extrahiert die Abfrage alle Daten im Datensatzsatz. Nach Abschluss der Abfrage kann die Verbindung sofort geschlossen werden und lokale Cursor können für den Zugriff auf Daten verwendet werden die Zukunft, was das Lösen der Verbindung erleichtert. Die Verwendung lokaler Recordsets ist wichtig für den Zugriff auf Remote-Datendienste, bei denen die Daten offline verwendet werden müssen. Ist sie jedoch auch für normale Anwendungen hilfreich?
Als nächstes fügen wir das CursorLocation-Attribut hinzu und schließen die Verbindung (CLIENT1.asp), nachdem wir das Recordset geöffnet haben:
Kopieren Sie den Codecode wie folgt:
Setze objRS = Server.CreateObject(ADODB.Recordset)
objRS.CursorLocation = 2' adUseClient
objRS.ActiveConnection = Anwendung(Conn)
objRS.LockType = 1?' adLockReadOnly
objRS.Open Application(SQL)
objRS.ActiveConnection = Nichts
Theoretisch würde dieser Ansatz aus zwei Gründen der Effizienz zugutekommen: Erstens vermeidet er das wiederholte Anfordern von Daten über die Verbindung beim Verschieben zwischen Datensätzen, zweitens verringert er den Ressourcenbedarf. Aus der obigen Tabelle geht jedoch hervor, dass die Verwendung eines lokalen Recordsets offensichtlich nicht zur Verbesserung der Effizienz beiträgt. Dies kann daran liegen, dass der Cursor bei Verwendung eines lokalen Recordsets unabhängig von den Programmeinstellungen immer zu einem statischen Typ wird.
Regel 6 lautet wie folgt:
lDies sollte vermieden werden, es sei denn, die Lokalisierung des Recordsets ist wirklich erforderlich.
10. Welche Methode ist am effizientesten, um Feldwerte in einem Datensatz zu referenzieren?
10.1 Testen
Bisher haben wir uns namentlich auf Feldwerte im Recordset bezogen. Da bei dieser Methode jedes Mal das entsprechende Feld gefunden werden muss, ist sie nicht sehr effizient. Um dies zu demonstrieren, verweisen wir im folgenden Test auf den Wert eines Felds anhand seines Index in der Sammlung (ADO__08.asp):
Kopieren Sie den Codecode wie folgt:
'Daten schreiben
Do While Not objRS.EOF
Response.Write(_
<TR> & _
<TD> & objRS(0) & </TD> & _
<TD> & objRS(1) & </TD> & _
<TD> & objRS(2) & </TD> & _
<TD> & objRS(3) & </TD> & _
<TD> & objRS(4) & </TD> & _
<TD> & objRS(5) & </TD> & _
<TD> & objRS(6) & </TD> & _
</TR> _
)
objRS.MoveNext
Schleife
Wie erwartet gibt es auch eine kleine Änderung beim Seitenaufwand (möglicherweise aufgrund einer leichten Reduzierung des Codes). Allerdings ist die Verbesserung der Anzeigezeit bei diesem Ansatz deutlich spürbar.
Im nächsten Test binden wir alle Felder einzeln an Variablen (ADO__09.asp):
Kopieren Sie den Codecode wie folgt:
Wenn objRS.EOF Dann
Response.Write (Keine Datensätze gefunden)
Anders
'Überschriften schreiben
...
Dimmen Sie fld0
Dimmen Sie fld1
Dimmen Sie fld2
Dimmen Sie fld3
Dimmen Sie fld4
Dimmen Sie fld5
Dimmen Sie fld6
Setze fld0 = objRS(0)
Setze fld1 = objRS(1)
Setze fld2 = objRS(2)
Setze fld3 = objRS(3)
Setze fld4 = objRS(4)
Setze fld5 = objRS(5)
Setze fld6 = objRS(6)
'Daten schreiben
Do While Not objRS.EOF
Response.Write(_
<TR> & _
<TD> & fld0 & </TD> & _
<TD> & fld1 & </TD> & _
<TD> & fld2 & </TD> & _
<TD> & fld3 & </TD> & _
<TD> & fld4 & </TD> & _
<TD> & fld5 & </TD> & _
<TD> & fld6 & </TD> & _
</TR> _
)
objRS.MoveNext
Schleife
Setze fld0 = Nichts
Setze fld1 = Nichts
Setze fld2 = Nichts
Setze fld3 = Nichts
Setze fld4 = Nichts
Setze fld5 = Nichts
Setze fld6 = Nichts
Response.Write(</TABLE>)
Ende wenn
Das ist die bisher beste Platte. Bitte beachten Sie, dass die Anzeigezeit eines einzelnen Datensatzes auf weniger als 0,45 Millisekunden reduziert wurde.
Die oben genannten Skripte erfordern alle ein gewisses Verständnis für den Aufbau des Ergebnisdatensatzes. Beispielsweise verwenden wir Feldnamen direkt in Spaltenüberschriften, um jeden Feldwert einzeln zu referenzieren. Im folgenden Test werden nicht nur die Felddaten durch Durchlaufen der Feldsammlung abgerufen, sondern auch die Feldtitel werden auf die gleiche Weise abgerufen. Dies ist eine dynamischere Lösung (ADO__10.asp).
Kopieren Sie den Codecode wie folgt:
Wenn objRS.EOF Dann
Response.Write (Keine Datensätze gefunden)
Anders
'Überschriften schreiben Response.Write(<TABLE BORDER=1><TR>)
Für jedes objFld in objRS.Fields
Response.Write(<TH> & objFld.name & </TH>)
Nächste
Response.Write(</TR>)
'Daten schreiben
Do While Not objRS.EOF
Response.Write(<TR>)
Für jedes objFld in objRS.Fields
? Response.Write(<TD> & objFld.value & </TD>)
Nächste
Response.Write(</TR>)
objRS.MoveNext
Schleife
Response.Write(</TABLE>)
Ende wenn
Wie Sie sehen, hat die Codeleistung abgenommen, ist aber immer noch schneller als ADO__07.asp.
Das nächste Testbeispiel ist ein Kompromiss der beiden vorherigen Methoden. Wir werden die dynamische Funktion weiterhin beibehalten und gleichzeitig die Leistung verbessern, indem wir Feldreferenzen in dynamisch zugewiesenen Arrays speichern:
Kopieren Sie den Codecode wie folgt:
Wenn objRS.EOF Dann
Response.Write (Keine Datensätze gefunden)
Anders
Dim fldCount
fldCount = objRS.Fields.Count
Dim fld()
ReDim fld(fldCount)
Dim ich
Für i = 0 bis fldCount-1
Setze fld(i) = objRS(i)
Nächste
'Überschriften schreiben
Response.Write(<TABLE BORDER=1><TR>) Für i = 0 bis fldCount-1
Response.Write(<TH> & fld(i).name & </TH>)
Nächste
Response.Write(</TR>)
'Daten schreiben
Do While Not objRS.EOF
Response.Write(<TR>)
Für i = 0 bis fldCount-1
Response.Write(<TD> & fld(i) & </TD>)
Nächste
Response.Write(</TR>)
objRS.MoveNext
Schleife
Für i = 0 bis fldCount-1
Setze fld(i) = Nichts
Nächste
Response.Write(</TABLE>)
Ende wenn
Obwohl es die vorherigen Besten nicht übertrifft, ist es schneller als die ersten paar Beispiele und hat den Vorteil, dass es jeden Satz von Datensätzen dynamisch verarbeiten kann.
Im Vergleich zum vorherigen Testcode wurde der folgende Testcode grundlegend geändert. Es verwendet die GetRows-Methode des Recordset-Objekts, um das Array für die Iteration über die Daten zu füllen, anstatt direkt auf das Recordset selbst zuzugreifen. Beachten Sie, dass das Recordset unmittelbar nach dem Aufruf von GetRows auf Nothing gesetzt wird, was bedeutet, dass Systemressourcen so schnell wie möglich freigegeben werden. Beachten Sie außerdem, dass die erste Dimension des Arrays die Felder und die zweite Dimension die Zeilen darstellt (ADO__12.asp).
Kopieren Sie den Codecode wie folgt:
Wenn objRS.EOF Dann
Response.Write (Keine Datensätze gefunden)
objRS.Schließen
Setze objRS = Nichts
Anders
'Überschriften schreiben
...
'Array festlegen
Dim arrRS
arrRS = objRS.GetRows
'Datensatz vorzeitig schließen
objRS.Schließen
Setze objRS = Nichts
'Daten schreiben
DimnumRows
DimnumFlds
Dunkle Reihe
Dim fld
numFlds = Ubound(arrRS, 1)
numRows = Ubound(arrRS, 2)
Für row= 0 bis numRows
Response.Write(<TR>)
Für fld = 0 bis numFlds
Response.Write(<TD> & arrRS(fld, row) & </TD>)
Nächste
Response.Write(</TR>)
Nächste
Response.Write(</TABLE>)
Ende wenn
Bei Verwendung der GetRows-Methode wird das gesamte Recordset in ein Array extrahiert. Obwohl es zu Ressourcenproblemen kommen kann, wenn der Datensatz extrem groß ist, ist der Zugriff auf die Daten in einer Schleife tatsächlich schneller, da Funktionsaufrufe wie MoveNext und die Prüfung auf EOF abgebrochen werden.
Geschwindigkeit hat ihren Preis, jetzt gehen die Metadaten des Recordsets verloren. Um dieses Problem zu lösen, können wir vor dem Aufruf von GetRows die Header-Informationen aus dem Recordset-Objekt extrahieren. Darüber hinaus können auch der Datentyp und andere Informationen im Voraus extrahiert werden. Beachten Sie außerdem, dass der Leistungsvorteil beim Testen nur dann auftritt, wenn der Datensatz größer ist.
Im letzten Test dieses Satzes verwenden wir die GetString-Methode des Recordsets. Die GetString-Methode extrahiert das gesamte Recordset in eine große Zeichenfolge und ermöglicht Ihnen die Angabe des Trennzeichens (ADO__13.asp):
Kopieren Sie den Codecode wie folgt:
Wenn objRS.EOF Dann
Response.Write (Keine Datensätze gefunden)
objRS.Schließen
Setze objRS = Nichts
Anders
'Überschriften schreiben
...
'Array festlegen
StrTable dimmen
strTable = objRS.GetString (2, , </TD><TD>, </TD></TR><TR><TD>)
'Datensatz vorzeitig schließen
objRS.Schließen
Setze objRS = Nichts
Response.Write(strTable & </TD></TR></TABLE>)
Ende wenn