Performance is a feature. You have to engineer for performance up front, or you'll have to rewrite your application later. That said, what are some good strategies for maximizing Active Server Pages (ASP) application performance?
This article describes techniques for optimizing ASP applications and Visual Basic® Scripting Edition (VBScript). This article discusses a number of pitfalls. The suggestions listed in this article have been tested at http://www.microsoft.com and other sites, and the results have been very significant. This article assumes that you already have a basic understanding of ASP development, including VBScript and/or JScript, ASP Application, ASP Session, and other ASP inherent objects (Request, Response, and Server).
Typically, ASP performance depends primarily on many factors other than the ASP code itself. Rather than list all the information in one article, we list performance-related resources at the end of the article. These links cover ASP and non-ASP topics, including ActiveX® Data Objects (ADO), Component Object Model (COM), databases, and Internet Information Server (IIS) configuration. These are some of our favorite links - be sure to check them out.
Tip 1: Cache frequently used data on the Web server
A typical ASP page retrieves data from a back-end data store and then converts the results into Hypertext Markup Language (HTML). Regardless of the speed of the database, retrieving data from memory is always much faster than retrieving data from the back-end data store. Reading data from a local hard drive is also generally faster than retrieving data from a database. Therefore, performance can often be improved by caching data on the Web server (stored in memory or on disk).
Caching is the traditional way of trading space for time. If you cache the right content, you can see a significant improvement in performance. For caching to be effective, data that is frequently reused must be saved, and recomputing this data requires a (moderately) large overhead. If the cache is all stale data, it will cause memory waste.
Data that changes infrequently is a good candidate for caching because you don't have to worry about syncing that data with the database over time. Combo box lists, reference tables, DHTML fragments, Extensible Markup Language (XML) strings, menu items, and site configuration variables (including data source names (DSNs), Internet Protocol (IP) addresses, and Web paths) are all good caches Candidate content. Note that you can cache a "representation" of the data without caching the data itself. If the ASP page changes rarely and is expensive to cache (for example, an entire product catalog), you should consider generating the HTML in advance rather than redisplaying it in response to each request.
Where should the data be cached and what caching strategies are there? Typically, data is cached in the Web server's memory or disk. The next two tips cover both methods.
Tip 2: Cache frequently used data in Application or Session objects.
ASP Application and Session objects provide convenient containers for caching data in memory. You can assign data to Application and Session objects, and the data remains in memory between HTTP calls. Session data is stored separately for each user, while Application data is shared among all users.
When should data be loaded into Application or Session? Typically, data is loaded when the Application or Session is started. To load data during Application or Session startup, add appropriate code to Application_OnStart() or Session_OnStart() respectively. These functions should be in Global.asa, if not you can add them. This data can also be loaded the first time it is needed. To do this, add some code to the ASP page (or write a reusable script function) to check whether the data exists and, if not, load the data. This is a traditional performance technique called "lazy evaluation" - not computing a value until you know you need it. For example:
<%
Function GetEmploymentStatusList
Dim d
d = Application(?EmploymentStatusList?)
If d = ??Then
' FetchEmploymentStatusList function (not shown)
' fetches data from DB, returns an Array
d = FetchEmploymentStatusList()
Application(?EmploymentStatusList?) = d
End If
GetEmploymentStatusList = d
End Function
%>
Similar functions can be written for each data block required.
In what format should the data be stored? Any variant type can be stored because all script variables are variant types. For example, you can store strings, integers, or arrays. Typically, you will store the contents of an ADO recordset in one of these variable types. To get data from an ADO recordset, you can manually copy the data into VBScript variables, one field at a time. It's faster and easier to use one of the ADO recordset persistence functions GetRows(), GetString(), or Save() (ADO 2.5). The details are beyond the scope of this article, but here is an example of a function that uses GetRows() to return an array of recordset data:
' Get Recordset, return as an Array
Function FetchEmploymentStatusList
Dimrs
Set rs = CreateObject(?ADODB.Recordset?)
rs.Open ?select StatusName, StatusID from EmployeeStatus?, _
?dsn=employees;uid=sa;pwd=;?
FetchEmploymentStatusList = rs.GetRows() ? Return data as an Array
rs.Close
Setrs=Nothing
End Function
further improves the above example by caching HTML as a list instead of an array. Here is a simple example:
' Get Recordset, return as HTML Option list
Function FetchEmploymentStatusList
Dim rs, fldName, s
Set rs = CreateObject(?ADODB.Recordset?)
rs.Open ?select StatusName, StatusID from EmployeeStatus?, _
?dsn=employees;uid=sa;pwd=;?
s = ?<select name=??EmploymentStatus??>? & vbCrLf
Set fldName = rs.Fields(?StatusName?) ' ADO Field Binding
Do Until rs.EOF
' Next line violates Don't Do String Concats,
' but it's OK because we are building a cache
s = s & ? <option>? & fldName & ?</option>? & vbCrLf
rs.MoveNext
Loop
s = s & ?</select>? & vbCrLf
rs.Close
Set rs = Nothing ' See Release Early
FetchEmploymentStatusList = s ' Return data as a String
End Function
Under appropriate conditions, the ADO recordset itself can be cached in the Application or Session scope. There are two caveats:
ADO must be marked as free-threaded and disconnected recordsets must be used.
If these two requirements are not guaranteed, do not cache the ADO recordset. In the following "Non-agile components" and "Don't cache connections" tips, we discuss the dangers of storing COM objects in the Application or Session scope.
When you store data in the Application or Session scope, the data remains there until you change it programmatically, the Session expires, or the Web application is restarted. What if the data needs to be updated? To manually force an update to Application data, you can access an administrator-only ASP page to update the data. Alternatively, you can automatically refresh the data at regular intervals through a function. The following example stores a timestamp with cached data and refreshes the data after a certain period of time.
<%
' error handing not shown...
Const UPDATE_INTERVAL = 300 ' Refresh interval, in seconds
' Function to return the employment status list
Function GetEmploymentStatusList
UpdateEmploymentStatus
GetEmploymentStatusList = Application(?EmploymentStatusList?)
End Function
' Periodically update the cached data
Sub UpdateEmploymentStatusList
Dim d, strLastUpdate
strLastUpdate = Application(?LastUpdate?)
If (strLastUpdate = ??) Or _
(UPDATE_INTERVAL < DateDiff(?s?, strLastUpdate, Now)) Then
' Note: two or more calls might get in here. This is okay and will simply
' result in a few unnecessary fetches (there is a workaround for this)
' FetchEmploymentStatusList function (not shown)
' fetches data from DB, returns an Array
d = FetchEmploymentStatusList()
' Update the Application object. Use Application.Lock()
' to ensure consistent data
Application.Lock
Application(?EmploymentStatusList?) = Events
Application(?LastUpdate?) = CStr(Now)
Application.Unlock
End If
End Sub
See World's Fastest ListBox with Application Data, which also has an example.
Be aware that caching large arrays in Session or Application objects is not a good practice. The syntax of the scripting language requires that the entire array must be temporarily copied before accessing any element of the array. For example, if you cache a 100,000-element array of strings that maps U.S. zip codes to local weather stations in an Application object, ASP must first copy all 100,000 weather stations into a temporary array. Only then can a string be extracted. In this case, it would be better to build a custom component with a custom method to store the weather station - or use a dictionary component.
Just another warning, don't throw the baby out with the bathwater: arrays can be quickly looked up and stored in memory as adjacent key data pairs. Indexing a dictionary is much slower than indexing an array. You should choose the data structure that provides the best performance for your situation.
Tip 3: Cache data and HTML on the Web server's disk
Sometimes there may be too much data to cache in memory. "Too many" is just a way of saying it depends on how much memory you want to consume, as well as how many items you need to cache and how often you want to retrieve them. In any case, if the data is too much to be cached in memory, consider caching the data on the Web server's hard drive as a text or XML file. Data can be cached on disk and in memory at the same time to establish the most appropriate caching strategy for your site.
Note that when measuring the performance of a single ASP page, retrieving data from disk may not necessarily be faster than retrieving data from a database. But caching reduces the load on the database and network. Under heavy load, this can greatly improve overall throughput. This is very effective when caching the results of expensive queries (such as multi-table joins or compound stored procedures) or large result sets. As always, test the pros and cons of several options.
ASP and COM provide tools for setting up disk-based caching solutions. The ADO recordset Save() and Open() functions save and load recordsets from disk. You can use these methods to rewrite the code example in the Application data caching technique above, using Save() of the file instead of writing the code to the Application object.
There are a few other components that work with files:
Scripting.FileSystemObject lets you create, read, and write files.
The Microsoft® XML parser (MSXML) provided with Internet Explorer supports saving and loading XML documents.
The LookupTable object (used on MSN, for example) is the best choice for loading simple lists from disk.
Finally, consider caching a representation of the data on disk rather than the data itself. The pre-converted HTML can be stored on disk in .htm or .asp files, and hyperlinks can point directly to these files. You can use commercial tools, such as XBuilder, or the Microsoft® SQL Server® Internet Publishing feature to automate the process of generating HTML. Alternatively, you can place the HTML code snippet in an .asp file. You can also use FileSystemObject to read HTML files from disk, or use XML to convert them early.
Tip 4: Avoid caching non-agile components in Application or Session objects
Although caching data in Application or Session objects is a good practice, caching COM objects has serious pitfalls. Typically, people tend to cache frequently used COM objects into Application or Session objects. Unfortunately, many COM objects (including all objects written in Visual Basic 6.0 or earlier) cause serious bottlenecks when stored in Application or Session objects.
Specifically, when any non-agile component is cached in the Session or Application object, it will cause a performance bottleneck. An agile component is a component marked with ThreadingModel=Both, which aggregates a Free-threaded marshaler (FTM); or a component marked with ThreadingModel=Neutral. (The Neutral model is new for Windows® 2000 and COM+.) The following components are not agile:
Free-threaded components (unless they aggregate FTM).
Apartment thread components.
Single threaded component.
Configured components (Microsoft Transaction Server (MTS)/COM+ libraries and server packages/applications) are not agile unless they are Neutral threads. Apartment-threaded components and other non-agile components are best suited at page scope (that is, they are created and destroyed on a single ASP page).
In IIS 4.0, components marked with ThreadingModel=Both are considered agile. In IIS 5.0, this alone is not enough. Components must not only be marked Both, but must also be aggregated FTM. The article on agility describes how to aggregate FTM with C++ components written in the Active Template Library. Be aware that if a component caches interface pointers, those pointers themselves must be agile or must be stored in the COM common interface table (GIT). If you cannot recompile a Both thread component to aggregate FTM, you can mark the component with ThreadingModel=Neutral. Alternatively, if you do not want IIS to perform agility checks (therefore, you can allow non-agile components to be stored in the Application or Session scope), you can set AspTrackThreadingModel to True in the metabase. Changing AspTrackThreadingModel is not recommended.
IIS 5.0 will throw an error if you want to store a non-agile component created with Server.CreateObject in an Application object. You can avoid this error by using <object runat=server scope=application ...> in Global.asa, but this is not recommended as it can lead to pooling and serialization, described below.
What happens if you cache non-agile components? Non-agile components cached in the Session object lock the Session to the ASP worker thread. ASP maintains a pool of worker threads to handle requests. Normally, a new request is always handled by the first available worker thread. If the Session is locked to a thread, the request must wait until its associated thread is available. Here's an analogy that might help: You go to a supermarket, pick out some items, and pay at the checkout counter #_3. Thereafter, whenever you pay for an item in that supermarket, you always have to pay at checkout #_3, even if there are fewer or no queues at other checkouts.
Storing non-agile components in the Application scope has an even worse impact on performance. ASP must create a special thread to run non-agile components stored in the Application scope. This has two consequences: all calls must be funneled to this thread, and all calls are queued. "Pooling" means that the parameters must be stored in a shared area of memory; perform an expensive context switch to a special thread; execute the component's method; pool the results into the shared area; perform another expensive context switch, Return control to the original thread. "Serialization" means that only one method is run at a time. Two different ASP worker threads cannot execute multiple methods on a shared component simultaneously. This eliminates concurrency, especially on multi-processor computers. To make matters worse, all non-Agile Application-scoped components share a single thread (the host STA), so the impact of serialization is even more significant.
What can I do? Here are some general rules. If you write objects using Visual Basic (6.0) or earlier, do not cache them in Application or Session objects. If you don't know the threading model of an object, don't cache it. Do not cache non-agile objects, instead create and release them on each page. Objects run directly on the ASP worker thread, so there is no pooling or serialization. If the COM objects are running on an IIS server, performance is acceptable if they do not take a long time to initialize and delete. Note that single-threaded objects should not be used in this way. Be careful - VB can create single-threaded objects! If you must use a single-threaded object (such as a Microsoft Excel spreadsheet) like this, don't expect high throughput.
When ADO is marked as free-threaded, ADO recordsets can be safely cached. To mark ADO as free-threaded, use the Makfre15.bat file, which is usually located in the directory \Program FilesCommonSystemADO.
Warning If you use Microsoft Access as your database, you should not mark ADO as free-threaded. The ADO recordset must also be disconnected. In general, if you do not control the ADO configuration in your site (for example, you are an independent software vendor [ISV] selling Web applications to customers who manage their own configurations), it is best not to cache recordsets.
Dictionary components are also agile objects. LookupTable loads its data from a data file and can be used for combo box data and configuration information. The PageCache object in Duwamish Books provides dictionary syntax, as does Caprock Dictionary. These objects or their derived objects can form the basis of an effective caching strategy. Note that Scripting.Dictionary objects are not agile and should not be stored in Application or Session scopes.
Tip 5: Don't cache database connections in the Application or Session object
. Caching ADO connections is generally a poor strategy. If a Connection object is stored in the Application object and used in all pages, then all pages will compete for this connection. If the Connection object is stored in the ASP Session object, a database connection will be created for each user. This will negate the advantages of connection pooling and put unnecessary pressure on the Web server and database.
Instead of caching database connections, you can create and delete ADO objects in each ASP page that uses ADO. This is efficient because IIS has built-in database connection pooling. To be more precise, IIS automatically enables OLEDB and ODBC connection pooling. This ensures that connections created and deleted on every page will be valid.
Because the connected recordset stores a reference to the database connection, you should not cache the connected recordset in the Application or Session object. However, you can safely cache disconnected recordsets that do not hold a reference to their data connection. To disconnect a recordset, perform the following two steps:
Set rs = Server.CreateObject(?ADODB.RecordSet?)
rs.CursorLocation = adUseClient ' step 1
' Populate the recordset with data
rs.Open strQuery, strProv
' Now disconnect the recordset from the data provider and data source
rs.ActiveConnection = Nothing ' step 2
More detailed information about connection pooling can be found in the ADO and SQL Server reference material.
Tip 6: Use Session Objects Properly
Now that we've discussed the advantages of caching in Applications and Sessions, let's discuss avoiding the use of Session objects. As discussed below, Session has several disadvantages when used with busy sites. "Busy" generally means a site that requires hundreds of pages per second or thousands of simultaneous users. This tip is even more important for sites that must scale horizontally—that is, those that utilize multiple servers to handle load or achieve fault tolerance. For smaller sites, such as intranet sites, if you want to realize the benefits brought by Session, the system overhead will inevitably increase.
In short, ASP automatically creates a Session for each user who accesses the Web server. Each Session requires about 10 KB of memory overhead (the main thing is that the data is stored in the Session), which slows down all requests. The Session remains valid until the configured timeout period (usually 20 minutes) elapses.
The biggest problem with Session is not performance, but scalability. Session cannot span several Web servers. Once a Session is created on one server, its data remains there. This means that if you use Session in a Web server farm, you must design a policy that always sends each user request to the server where the user's Session is located. This is called "gluing" the user to the Web server. The term "sticky session" is derived from this. If the Web server crashes, "sticked" users will lose their session state because the session is not stuck to disk.
Strategies for achieving sticky sessions include hardware and software solutions. Solutions such as Network Load Balancing in Windows 2000 Advanced Server and Cisco's Local Director can implement sticky sessions at the expense of some degree of scalability. These solutions are imperfect. It is not recommended to deploy your own software solution at this time (we used to use ISAPI filters and URL transformations, etc.).
Application objects also do not span multiple servers; if you must share and update Application data across a farm of Web servers, you must use a back-end database. However, read-only Application data is still useful in a Web server farm.
Most mission-critical sites require at least two Web servers, if only to increase uptime (to handle failover and server maintenance). Therefore, when designing mission-critical applications, you must implement "sticky sessions" or simply avoid using Sessions and any other state management technology that stores user state on a single Web server.
If you are not using Sessions, be sure to close them. You can do this for an application through Internet Services Manager (see the ISM documentation). If you decide to use Sessions, there are ways you can mitigate their impact on performance.
You can move content that does not require a Session (such as help screens, visitor areas, etc.) to another ASP application that has the Session closed. You can prompt ASP on a page-by-page basis that you no longer need the Session object on that page, using the following directive at the top of the ASP page:
<% @EnableSessionState=False %>
A good reason for using this directive is that these Session has an interesting problem with framesets. ASP guarantees that only one request is executed in the Session at any time. This ensures that if the browser requests multiple pages for a user, only one ASP request touches the Session at a time, thus avoiding multi-threading problems that occur when accessing the Session object. Unfortunately, all pages in a frameset will be displayed serially, one after the other, rather than simultaneously. Users may have to wait for a long time to see all frames. Moral of the story: If some frameset pages do not rely on Session, be sure to tell ASP using the @EnableSessionState=False directive.
There are many ways to manage Session state that can replace the use of Session objects. For small amounts of state (less than 4 KB), we generally recommend using Cookies, QueryString variables, and implicit variables. For larger data volumes, such as shopping carts, a back-end database is the most suitable choice. Much has been written about state management techniques in Web server farms. For more information, see Session status reference.
Tip 7: Encapsulate code in COM objects
If you have a lot of VBScript or JScript, you can often improve performance by moving your code into compiled COM objects. Compiled code usually runs faster than interpreted code. Compiled COM objects can access other COM objects through "early binding", which is a more efficient method of calling COM objects than "late binding" used by scripts.
Encapsulating code in COM objects has several advantages (besides performance):
COM objects help separate presentation logic from business logic.
COM objects ensure code reuse.
Many developers find that code written in VB, C++, or Visual J++ is easier to debug than ASP.
COM objects also have disadvantages, including initial development time and requiring different programming skills. Note that encapsulating a small amount of ASP may cause performance degradation without improving performance. This situation usually occurs when a small amount of ASP code is encapsulated into a COM object. In this case, the overhead of creating and calling the COM object outweighs the advantages of the compiled code. Trial and error should be used to determine what combination of ASP script and COM object code produces the best performance. Note that there are significant improvements in scripting and ADO performance in Windows 2000/IIS 5.0 compared to Microsoft Windows NT® 4.0/IIS 4.0. Therefore, with the introduction of IIS 5.0, the performance advantage of compiled code over ASP code has decreased.
For a detailed discussion of the advantages and disadvantages of using COM in ASP, see ASP Component Guidelines and Programming Distributed Applications with and Microsoft Visual Basic 6.0. If you deploy COM components, it is especially important to test them under load. In fact, all ASP applications should be load tested as a matter of course.
Tip 8: Get resources later and release them earlier.
Here is a little tip for your reference. Generally speaking, it is better to obtain resources later and release them earlier. This applies to COM objects as well as file handles and other resources.
This optimization method is mainly used for ADO connections and recordsets. When you are done with a recordset, say after displaying a table and its data, you should release it immediately rather than waiting until the end of the page. It is best practice to set the VBScript variable to Nothing. Don't let a recordset go out of scope. Also, release any related Command or Connection objects (don't forget to call Close() before setting the recordset or connection to = Nothing). This shortens the time the database has to prepare resources for you and releases the database connection to the connection pool as quickly as possible.
Tip 9: Out-of-Process Execution Trades Performance for Reliability
Both ASP and MTS/COM+ have configuration options that allow you to trade off reliability with performance. When building and deploying applications, you should know how to balance performance with both.
ASP options configure ASP applications to run in one of three ways. In IIS 5.0, the term "isolation level" was introduced to describe these options. The three isolation levels are low-level, medium-level and high-level:
low-level isolation. This is supported in all versions of IIS and is the fastest. It runs ASP in Inetinfo.exe, which is the main IIS process. If the ASP application crashes, so will IIS. (To restart IIS under IIS 4.0, the Web site administrator should monitor the site using a tool such as InetMon and enable a batch file to restart the server if the server fails. IIS 5.0 introduced reliable restart, which method to automatically restart a failed server).
Intermediate isolation. IIS 5.0 introduced this new level, which is called the out-of-process level because ASP runs outside the IIS process. In intermediate isolation, all ASP applications configured to run as intermediate isolation share a process space. This reduces the number of processes required to run multiple out-of-process ASP applications on a single server. Medium isolation is the default isolation level in IIS 5.0.
Advanced isolation. This level is supported in IIS 4.0 and IIS 5.0, and advanced isolation is also out-of-process. If ASP crashes, the Web server does not crash. The ASP application will automatically restart the next time an ASP request is made. In advanced isolation, each ASP application configured to run as advanced isolation runs in its own process space. Doing this protects ASP applications from interfering with each other. The disadvantage is that it requires a separate process for each ASP application. When many applications must run on a single server, system overhead increases significantly.
Which option is best? In IIS 4.0, running out of process will significantly reduce performance. In IIS 5.0, many improvements have been made to minimize the overhead caused by running ASP applications out of process. In fact, in the vast majority of tests, ASP out-of-process applications in IIS 5.0 ran faster than in-process applications in IIS 4.0. Regardless, on both platforms, in-process (low isolation level) performs best. However, if the access rate is relatively low or the maximum throughput is low, the advantages of a low isolation level are less obvious. Therefore, setting a low isolation level may only be necessary if you require hundreds or thousands of pages per second per Web server. As always, test multiple configurations to determine which compromise you want to make.
Note that when you run ASP out-of-process applications (medium or high isolation), they run in MTS in NT4 and in COM+ in Windows 2000. That is, in NT4 they run in Mtx.exe; in Windows 2000, they run in DllHost.exe. You can see these processes running in Task Manager. You can also see how IIS configures an MTS package or COM+ application for an out-of-process ASP application.
COM Options COM components also have three configuration options, although they are not exactly similar to the ASP options. COM components can be "unconfigured", configured as a library application, or configured as a server application. "Unconfigured" means that the component is not registered with COM+. Components will run in the process space of the calling program, that is, they are "in-process". Library applications are also in-process, but use COM+ services, including security, transactions, and context support. Server applications are configured to run within their own process space.
You can see that unconfigured components have slight advantages over library applications. Library applications have greater performance advantages than server applications. This is because library applications run in the same process as ASP, while server applications run in their own processes. Inter-process calls are more expensive than intra-process calls. Furthermore, when passing data such as recordsets between processes, all data must be copied between the two processes.
trap! When using a COM server application, if you pass objects between ASP and COM, make sure that the objects perform "bundle by value" or MBV. Objects performing MBV copy themselves from one process to another. This is better than an approach where the object is still in the creator's process and another process calls the creating process repeatedly to use the object. A disconnected ADO recordset will be "clustered by value", a connected recordset will not. Scripting.Dictionary does not perform MBV and is not passed between processes. Finally, a note to VB programmers: MBV is not obtained by passing the parameter ByVal. MBV is performed by the original component author.
what to do?
If we were asked to suggest a reasonable configuration that balances performance and reliability, they would be the following:
In IIS 4.0, use ASP low isolation level and use the MTS server package.
On IIS 5.0, use ASP's medium isolation level and use a COM+ library application.
These are very general principles; hosting companies typically run ASP at medium or high isolation levels, while single-purpose Web servers can run at low isolation levels. Weigh the pros and cons and decide for yourself which configuration better suits your needs.
Tip 10: Use explicit options
Option Explicit should be used in .asp files. This directive is placed at the top of the .asp file and forces the developer to declare all variables to be used. Many programmers find this method helpful in debugging applications because it avoids the possibility of mistyping variable names and accidentally creating new variables (for example, MyXMLString=) instead of MyXLMString=....
Perhaps more importantly, declared variables are faster than undeclared variables. This way, every time the script uses an undeclared variable at runtime, it references it by name. On the other hand, variables are declared in order, either at compile time or run time. From now on, declared variables are referenced in this order. Because Option Explicit forces variable declaration, it ensures that all variables are declared, so access is fast.
Tip 11: Use local variables in subroutines and functions
Local variables are those variables declared within subroutines and functions. Within a function or subroutine, local variable access is faster than global variable access. The use of local variables will also make the code clearer, so local variables should be used whenever possible.
Tip 12: Copy frequently used data into script variables
When accessing COM objects in ASP, frequently used object data should be copied into script variables. Doing this reduces COM method calls, which are relatively expensive compared to accessing script variables. This technique also reduces expensive lookups when accessing Collection and Dictionary objects.
In general, if you plan to access object data more than once, you should put the data in script variables. The main target of this optimization is the Request variables (Form and QueryString variables). For example, your site can pass a QueryString variable named UserID. Let's say this UserID is referenced 12 times on a particular page. Instead of calling Request(?UserID?) 12 times, you can assign UserID to a variable at the top of the ASP page. Then use that variable throughout the page. This saves 11 COM method calls.
In fact, the cost of accessing the COM attribute or method is not so large. Let ’s take an example below to show that a certain common code (from grammar):
foo.bar.blah.baz = foo.bar.blah.qaz (1)
If foo.bar.blah.zaq = foo.bar.blah.abc then '...
When this code is running, the following occurs:
variable FOO is analyzed as global object.
The variable bar is parsed as a member of FOO. This is actually a COM method call.
The variable Blah was parsed as a member of FOO.BAR. This is another COM method call.
Variable QAZ was analyzed as a member of foo.bar.blah. Nothing, this is still a COM method call.
Call foo.bar.blah.quaz (1). COM method call again. Got it?
Execute steps 1 to step 3 again to analyze BAZ. The system does not know if the QAZ changes the object model, so you must perform steps 1 to 3 to analyze BAZ again.
Base analysis as a member of foo.bar.blah. Give attributes.
Perform step 1 to step 3 again to analyze ZAQ.
Execute steps 1 to step 3 again to analyze ABC.
As you can see, the efficiency is quite poor (and slow). The fast way to write this code with VBScript is:
set myObj = FOO.BAR.BLAH 'Do the Resolution of Blah Once
MyObj.baz = MyOBJ.QAZ (1)
If myObj.zaq = MyObj.abc then '...
If you use VBSCRIPT 5.0 or higher version, you can write this code in With statement:
with foo.bar.blah
.baz = .qaz (1)
If .zaq = .abc then '...
...
End with
paying attention to this technique is also applicable to VB program design.
Tip 13: Avoid re -determining the dimension of the array
to avoid the Redim array as much as possible. As far as performance is concerned, if the size of the computer's physical memory is limited, it is best to set the initial dimensions of the array to its most unfavorable case-or set the dimension to its best situation, and then re-determine the dimension as needed. This does not mean that if you know that you don't need memory, you can allocate a few megar bytes of memory.
The following code shows you inappropriate use of DIM and Redim.
<%
Dim myarray ()
Redim myarray (2)
MyRray (0) =? Hello?
Myarray (1) =? Good-Bye?
Myarray (2) =? Farewell?
...
'Some Other Code WHERE You End Up Needing More Space Happens, then ...
Redim Preserve Myarray (5)
MyRray (3) =? More stuff?
MyRray (4) =? Even more stuff?
MyRray (5) =? Yet more stuff?
%>
It is best to make the initial size of the array at the beginning (in this example, 5) is much better than the Redim array. You may waste some memory (if you do not use all elements), but the advantage is that the speed becomes faster.
Tip 14: Use the response buffer.
You can buffer the entire page to be output through the "response buffer". In this way, the amount of browser is reduced to the least, thereby improving overall performance. Each writing operation generates a lot of system overhead (in IIS and the amount of data sent through the network), so the less the writing operation, the better. Because it starts slowly and uses the Nagling algorithm (used to reduce the situation of network traffic jams), TCP/IP is much more efficient when sending some large data blocks than to send many small data blocks.
There are two methods to enable response buffer. The first, you can use the Internet Services Manager to enable the response buffer to the entire application. We recommend using this method to open the response buffer in IIS 4.0 and IIS 5.0. The second type can be added to the following code line at the nearly top of each ASP page to enable the response buffer:
< % Response.buffer = TRUE %>
This code line must be executed before any response data is written to the browser (that is, before any HTML appears before the ASP script and the use of the response.cookies set is set to set any cookies). Generally speaking, it is best to enable response buffer for the entire application. In this way, you don't have to write the above code line on the top of each page.
Response.Flush
There is a common complaint on the response buffer, that is, the user feels that the response speed of the ASP page is very slow (even if the entire response time is improved), because they must wait until the entire page is generated before they can see things. For a page with a long run, you can set response.buffer = false to disable the response buffer. However, a better strategy is to use the response.flush method. This method sends all HTMLs converted to the browser. For example, after the front 100 lines of the 1,000 lines, ASP can call Response.flush, and forcibly send the conversion result to the browser, so that users can see the head 100 lines before the remaining rows are prepared. This technology can gradually combine the response buffer with the browser.
(Note that in the example of the 1,000 lines above, many browsers will not start display tables before they see the closure </table>. Check if your target browser supports. There are multiple tables with less line and call Response.flush after each table.
This can avoid forced Internet Explorer to calculate the column width by measuring the content width ofeach
cell.
Do not talk about the method of generating a large page, this problem can also be solved by clever use of response.flush.
Tips 15: Batch processing of embedded script and response.write statement
vbscript syntax < % = Expression %> to write the value of "Expression" into the ASP output stream. If the response buffer is not enabled, every statement of the execution will be written into the browser with many small packets through the network. This is slow. And interspersed a small amount of script and HTML, it will cause switch between the script engine and HTML, thereby reducing performance. Therefore, use the following techniques: Use response.write to instead of tightly bundled embedded expressions. For example, in the following example, there is a writing operation of the response stream at each field of each line. There are many switches between each line between VBScript and HTML:
<Table>
< % For Each FLD in RS.Fields %>
<th> < % = FLD.NAME %> </th>
<%
Next
While Not RS.EOF
%>
<tr>
< % For Each FLD in RS.Fields %>
<td> < % = FLD.VAEUE %> </td>
<% Note
</tr>
<% rs.movenext
Wend %>
</table>
The following code is more effective, and each row has an operation of the response flow. All code is included in a VBScript block:
<Table>
<%
For Each FLD in RS.Fields
Response.write (? <th>? & FLD.NAME &? </TH>? & VBCRLF)
Next
While Not RS.EOF
Response.write (? <ter>?)
For Each FLD in RS.Fields %>
Response.write (? <TD>? & FLD.VALUE &? </TD>? & VBCRLF)
Next
Response.write? </Tr>?
Wend
%>
</table>
The effect of this technique is particularly effective when the response cushion is disabled. It is best to enable the response buffer, and then see if the response.write helps improve performance.
(In this specific example, establish an embedded loop of the table subject (While Not RS.EOF ...) can be replaced with a carefully constructed getstring.)
Skills 16: If the page needs to be completed for a long time, then execute Using response.isclientConnect before,
if user is urgent, they may give up the ASP page before you start their request. If they click refresh or moved to another page on the server, there is a new request waiting at the end of the ASP request queue, and there is a disconnected request in the middle of the queue. When the load of the server is very high (therefore, the request queue will be very long, the response time will become longer), and this will often happen, so that the situation can only make the situation worse. If the user is no longer connected, it is meaningless to execute the ASP page (especially the slow, large ASP page). You can use Response.IsclientConnected attributes to check this situation. If it returns FALSE, call Response.end and give up the rest of the page. In fact, IIS 5.0 has compiled this approach as a program-whenever ASP is about to execute a new request, it will check how long the request has been waiting in the queue. If you have been waiting there for more than 3 seconds, ASP will check whether the client is still connected, and if there is no connection, the request will be terminated immediately. You can use ASPQUEUECONNECTINECTESTTIME settings in the configuration database to set the timeout to adjust the timeout from 3 seconds to other values.
If the page takes a long time to execute it, you can also check the response.isClientConnect from time to time. When the response buffer is enabled, it is best to execute the response.flush from time to time, as the user knows what is happening.
Note that on IIS 4.0, unless you execute the response.write first, the response.IsClientConnect cannot work normally. If the buffer is enabled, you must also execute the response.flush. On IIS 5.0, there is no need to do this. In any case, there will be some expenses in Response.isClientConnect, so only one operation is spent at least (for example) 500 milliseconds (if you want to maintain the throughput of dozens of pages per second, this is a long time) It was used. Experience shows that you do not call it every time you repeatedly perform a tight cycle, such as many rows of the display table-calls every twenty or fifty lines may be appropriate.
Tip 17: Use the object of <Object> tag examples
if you want to quote the objects that are not used in all code paths (especially the objects of the server or application scope), and use the <Object Runat = Server ID = Objname> label statement in Global.asa in global.asa. They do not use the server.createObject method. Server.createObject can create an object immediately. If you no longer use the object in the future, you will waste resources. <Object ID = Objname> Label Objname, but it will not create Objname before its method or attribute is used for the first time.
This is another example of inert calculation.
Tips 18: For ado and other components, use Typelib to declare that
when using ADO, developers often join Adovbs.txt to access ADO's various constants. This file must be included in each page of the constant. This constant file is quite large, adding a lot of system overhead to the compilation time and script size of each ASP page.
IIS 5.0 introduces the function of binding to component type libraries. This allows you to quote the type library once and use it on each ASP page. Each page does not generate an overhead to compile constant files, and component developers do not have to create VBScript#_include files to use on ASP.
To access Ado Typelib and place the following statements in global.asa.
<!- Metadata name =? Microsoft Activex Data Objects 2.5 Library?
Type =? Typelib? UUID =? {00000205-0000-0010-8000-00aa006d2ea4}?->
Or
<!- Metadata type =? Typelib?
File =? C: Program Files Common Files System Ado msado15.dll? ->
Tips 19: Use the browser's verification function.
Now the browsers are available for some advanced functions such as XML, DHTML, Java applet and remote. Data service supports. Use these functions as much as possible. All these technologies can perform client -side verification and data cache, eliminating the round -trip from the web server. If you run a smart browser, then the browser can conduct some verifications for you (for example, check the credit card verification and whether it is valid). Use this function as much as possible. By reducing the round-trip between customers-servers, the load on the web server can be reduced, and network communication can be reduced (although the first page sent to the browser may be relatively large) and any back-end resources accessed by the server. In addition, users do not have to read a new page like living, so that the user feels better. Doing this does not mean that you can not verify the server-you should always conduct server-side verification. This prevents the client that generates error data from some reasons (such as hackers, or browsers without running client -side verification routines).
People have done a lot of work to develop HTML, which is "independent of browsers". It is precisely because of this worry that developers are unwilling to use popular browser functions, but these functions can have improved performance. For some real high -performance sites, you must care about the "access" of the browser. A good strategy is to optimize the page to make it adapt to the popular browser. With browser function components, the browser function can be detected in ASP. Microsoft FrontPage and other tools help design code suitable for browsers and specified HTML versions. See when Is Better Worse? Weight the technology trade-office to understand further discussion.
Tip 20: Avoid using string in a cyclic statement to connect
many people to create a string in a cyclic sentence, as shown below:
s =? <Table>? & Vbcrlf
For Each FLD in RS.Fields
s = s &? <TH>? & FLD.NAME &? </TH>?
Next
While Not RS.EOF
s = s & vbcrf &? <ter>?
For Each FLD in RS.Fields
s = s &? <TD>? & FLD.VALUE &? </TD>?
Next
s = s &? </tr>?
rs.MoveNext
Wend
s = s & vbcrf &? </Table>? & Vbcrip
Response.write s
There are some problems with this method. The first problem is that repeated string string needs to spend two square meters. To be more popular, the time spent on running this cyclic statement is directly proportional to the value of the record number of the record. To give a simpler example, you can explain this problem more clearly.
s = ??
For i = ASC (? A?) To ASC (? Z?)
s = s & chr (i)
Next
In the first iteration, you got a character string? A?. In the second iteration, VBScript must redistribute the string and copy two characters (? AB?) Into S. In the third iteration, it must re -assign S again and copy three characters into S. In N times (the 26th) iteration, it must be re -assigned and copy the N characters to S. A total of 1+2+3+...+n, that is, N*(n+1)/2 replication.
In the above record set, if there are 100 records and 5 fields, 100*5 = 500 times will be performed in the internal cycle. All replication and re -assigning time will be proportional to 500*500 = 250,000. This is too much for medium -sized records.
In this example, the code can be improved with response.write () or an embedded script (< % = FLD.VALUE %>) instead of the string in series to improve. If the response buffer is enabled (should), it will be faster, because response.write only attach the data to the end of the response buffer. It does not involve re -distribution, so efficiency is high.
In a specific case where the ADO record set is converted to the HTML table, you should consider using Getrows or GetString.
If a string string in JScript, it is recommended to use += operator, that is, using S +=? A string? Instead of using S = S +? A string?
Tips 21: Enable browsers and proxy slow existence
default, ASP is forbidden to cache in browsers and agents. This is meaningful, because in essence, the ASP page is dynamic, with potential information that is constantly changing over time. If the page is not required to refresh on each view, you should use the browser and proxy cache. This allows the browser and agents to use the "cache" copy of the page within a certain time, and you can control the length of time. The cache can greatly reduce the load on the server and shorten the waiting time of users.
Which dynamic page can be used as a page to cache? Let's take some examples:
Weather forecast page, on this page, the weather forecast is updated every 5 minutes.
List the homepage of news entries or press releases, it updates twice a day.
Common fund performance list, in this list, basic statistics information is updated every few hours.
Note that in the case of using a browser or an agent cache, the number of access recorded on the web server has decreased. If you want to accurately measure all page views or posts, you don't want to use a browser and agent cache.
The browser cache is controlled by the HTTP "expired" newspaper, and the header is sent to the browser by the Web server. ASP provides two simple mechanisms to send this newspaper. To set the page how many minutes after expiration, the response.expires property should be set. The following example tells the browser's content within 10 minutes:
< % Response.expires = 10 %>
If the response.expires is set to negative or 0, the cache is disabled. Be sure to use large negative numbers, such as -1000 (slightly more than one day) to avoid non-matching between the server and the browser clock. The second attribute response.expiresabsolute will allow you to set the specific time of the expiration of the content:
< % Response.expiresabsolute = #May 31,2001 13: 30: 15 # %>
You can set the expiration time without using the Response object, and write the <Meta> mark into HTML, and usually write in the <head> part of the HTML file. Some browsers will follow this instruction, while the agent is not.
<Meta http-equiv =? Expires? Value =? May 31,2001 13:30:15?>
Finally, you can use Response.cacheControl attribute to indicate whether the content can make the HTTP proxy cache. If this attribute is set to "PUBLIC", the proxy can cache this content.
< % Response.cacheControl =? Public? %>
By default, this attribute is set to "Private". Note that for the page that shows a specific data of a user, the proxy cache should not be enabled, because proxy may provide users with pages belonging to other users.
Tips 22: Use server.transfer instead of response.redirect
response.redirect to ask the browser to request another page. This function is often used to redirect the user to a login or error page. Because the new page is requested to the compulsory request, the browser must go back and forth twice to the web server, and the web server must handle one more request. IIS 5.0 introduces a new function Server.transfer, which will be executed to another ASP page on the same server. In this way, avoid the turn of the excess browser -web-server, thereby improving the overall system performance and shortening the response time of users. Check the "new direction" in the "redirect", which should be Server.transfer and Server.execute.
Please see Leveraging ASP in IIS 5.0 to learn about the complete list of new features of IIS 5.0 and ASP 3.0.
Tips 23:A related technique of
using a backline in the directory URL
is to ensure that the backline (/) is used in the URL in the directory.If you omit the backline, the browser will send a request to the server, just to tell the server, it is on the request directory. The browser will send a second request to attach the slash behind the URL. Only after that, the server can respond with the default document or directory list of the directory (if there is no default document and enable the directory browsing). Additional slash can save the first and useless residence. To facilitate user reading, you can omit the rear slope in the name.
For example, write:
<A href =? Http://msdn.microsoft.com/Workshop/? Title =? Msdn web
Workshop?> Http://msdn.microsoft.com/Workshop </a>
This is also applicable to the URL pointing to the homepage on the web site: Use the following: <A href =? Http://msdn.microsoft.com/?> Instead of using <a href =? Http://msdn.microsoft. com?>.
Tips 24: Avoid using server variables
to access server variables that make the Web site send a special request to the server and collect all server variables, not just the variable you request. This situation is similar to that in a moldy attic, find a file in a folder. When you want to find that file, you must go to the attic, find a folder first before you can find this file. When you ask the server variable, the situation is the same-when you ask the server variable for the first time, the performance will be affected. The subsequent request for other server variables will not affect performance.
Never access non -limited Request objects (for example, Request ("Data"). For items that are not in the project in the request.cookies, request.form, request.querystring or request.clientcertified, the implicit calls request.servervariables. Request.servervariables set is much slower than other sets.
Tips 25: The upgrade to the latest and best
system components is constant. We recommend that you upgrade them to the latest and best configurations. It is best to upgrade to Windows 2000 (therefore, it should also be upgraded to IIS 5.0, ADO 2.5, MSXML 2.5, Internet Explorer 5.0, VBScript 5.1 and JScript 5.1). On the multi -processor computer, the implementation of IIS 5.0 and ADO 2.5 can significantly improve performance. At Windows 2000, ASP can be expanded to four processors or more, and under IIS 4.0, ASP's scalability cannot exceed two processors. The more scripts and ADOs used in the application, the more performance will be improved after upgrading to Windows 2000.
If you can't upgrade to Windows 2000, you can upgrade to the latest versions of SQL Server, Ado, VBSCRIPT and JSCRIPT, MSXML, Internet Explorer, and NT 4 Service Packs. They can improve performance and reliability.
Tips 26: Optimized Web server
has multiple IIS optimization parameters to improve site performance. For example, for IIS 4.0, we often find that increasing ASP ProcessOrthreadMax parameters (see IIS documents) can significantly improve performance, especially on sites that are waiting for back -end resources (such as databases) or other intermediate products (such as screen brushes). . In IIS 5.0, you may find that ASP Thread Gating is more efficient than finding an aspprocessorthreadMax best settings, which is now known to everyone.
For good reference materials, see the following optimization IIS.
The best configuration settings depend on (some of these factors) application code, the system hardware and customer work load running. The only way to find the best setting is to perform performance testing, which is what we want to discuss in the next technique.
Tips 27: Performance tests,
as we have already said before, performance is a feature. If you want to improve the performance of the site, set a performance goal, and then gradually improve until you reach the target. No, no performance tests are performed. Generally, at the end of the project, it is too late to make the necessary structural adjustment, and your customers will be disappointed. Performance tests are performed as part of your daily test. Performance tests can be performed separately for a single component, such as for the ASP page or COM object, or the site as a whole as a whole.
Many people use a single browser request page to test the performance of the web site. Doing this will give you a feeling that the response ability of the site is very good, but this does not actually tell you how the performance of the site under the load conditions.
Under normal circumstances, if you want to test performance accurately, you need a special test environment. This environment should include hardware, and its processor speed, processor quantity, memory, disk, network configuration, etc. are similar to the hardware of the production environment. Secondly, you must specify the working load of the client: how many users are at the same time, they send the frequency of requests, they click on the type of the page, and so on. If you have no data on the actual usage of the site, you must estimate the situation of use. Finally, you need a tool to simulate the work load of the client. With these tools, you can start answering questions such as "If I have n users who have N, how many servers do I need?" You can also find out the reasons for bottlenecks and optimize this goal.
Here are some good web load testing tools. We specially recommend Microsoft Web Application Stress (WAS) toolkit. WAS allows you to record the test script, and then simulate hundreds or thousands of users to access the web server. WAS reports many statistical information, including the number of requests per second, the distribution of time and error count. WAS has rich client interface and web -based interface. The web interface allows you to conduct remote testing.
Be sure to read IIS 5.0 Tuning Guide.
Tips 28: Reading resource links
are some excellent resource links related to performance. If you want to understand the relevant information, read the Developing Scalable Web Applications.
Resource optimization ASP script Developing Scalable Web Applications
Got Any Cache? Nancy Winnick Cluts is
Maximizing the Performance of Your Active Server Pages, Nancy Winnick Cluts
15 Seconds: Performance Section
Enhancing Performance in ASP -Part I, Wayne Plource with
WHEN Is Better Worse? Weighing the technology trade-office, nancy winnick cluts are
Speed and Optimization Resources, CHARLles Carroll
optimizes IIS
The Art and Science of Web Server
Tuning
H Internet
Information Service, Michael Stephenson is
the Tuning Internet Information Server Performance, Mike Moore is
navigating the maze of settings for web server performance, TODD WANKE G
Internet Informative Server 4.0 for Performance, Hans Hugli is
Ado and SQL Server
TEP TIPS: Accessing SQL Through Ado And asp, JD Meier is
Improve the Performance of your MDAC Application, Suresh Kannan is
Pooling in the Microsoft Data Access Components, LELAND AHLBECK and Don Willit
SQL Server: Performance Benchmarks and Guides
Improving the Performance of Data Access Components with IIS 4.0,,,,,,, 4.0,,, 4.0,,,, 4.0,,, 4.0,,, 4.0,,, 4.0,,, 4.0,,, 4.0,,, 4.0,,, 4.0,,,,, to, LELAND AHLBECK is
Microsoft Data Access Components (MDAC) and Activex Data Objects (Ado) Performance Tips, Leland Ahlbeck is
Microsoft SQL Server 7.0 Practical Perf ORMance Tuning and Optimization -The Server Perspective, Damien Lindauer
Microsoft SQL Server 7.0 Practical Performance Tuning and Optimization - The Application Perspective, Damien Lindauer is
Accessing RecordSets Over The Internet, Dino Esposito is
ASP
Component Guidelines, JD Meier
Q243548: Inf isO
: Design Guidelines for VB Components Under
Asp Threading ModelsExplained, Nancy Winnick Cluts
? USING ACTIVEX Components with Active Server Pages, Nancy Winnick Cluts is the
development activity server components with atl,
George Reilly Il Allain is
Building High-Performance Middle-Tier Components with C ++, Jon Flanders is
Active Server Pages and com Apartments, Don Box is holding
House of Com: Active Server Pages, Don Box is
House of Com: Contexts, Don Box is
House of Com: Performance Trade-OFFS of the Windows 2000 Component. ION Environment, Don Box is
Building Com Components that take full Advantage of Visual Basic and Scripting, Ivo Salmre is
Component Design Principles for MTS
Dictionary
Creating A Page Cache Object.
Onry Object: The Asp Team Creates A Lookup-Table Object, Robert Carter is
Caprock Dictionary
Site Server Commerce Edition Includes A Dictionary Component
session status
Q175167: Howto: Persisting Values with Sessions
q157906: Howto: Howto to Maintain Across the -Based Persisistence BehaviviVIVIARS FIX
Web Farm Headaches, Aaron Skonnard is
House of Com: Stateless Programming, Don Box's
performance
with performanceAnd the scalability
BluePrint for Building Web Sites using the microSoft Windows DNA Platform
Performance and Scalability Killer, George Reilly is
Microsoft Visual S Tudio Scalability Center
Fitch & Mather Stocks 2000
Tuning The FMSTOCKS Application
High-Performance Visual Basic Apps, Ken Spencer is
Duwamish Books, Phase 4
Top Windows DNA Performance Mistakes and How To Prevent them, Gary Geiger and Jon Pulsipher coincide with
the Building from Static HTML to High-Farms, Shawn Bice
Microsoft
Web Application Stress Tool
I can'T ENOUGH - Load Test Your Asp Application, JD Meier
Windows DNA Performance Kit
Monitoring Events In Distribute Applications Using Visual Studio Analyzer, MAI-LAN Tomsen
PROFESSIONAL
ACTIVE Server Pages 3.0, Wrox Press (especially Chapter 26: Optimizing Asp Performance, George Reilly Coincident with Matthew Gibbs).
Microsoft Internet Information Services 5.0 Resource Guide (with Windows 2000 Server Resource Kit), Microsoft Press.
Microsoft Internet Information Server Resource Kit (for IIS 4.0), Microsoft Press.
Programming district application of 6.0, Microsoft Press, Microsoft Press.
Effective com, Don Box, Keith Brown, Tim Ewald, and Chris Sells; Addison-Wesley.
Developing web usability: The Practice of Simplicity, Jakob Nielsen, New Riders.
Asp web site
microsoft technet for iis
learnasp.com
4guysfromrolla.com
15seconds.com
asptoday.com
asplists.com
. Many professional email lists include:
Fast Code!
ASP Advanced
Not newbiestate management
Scalability
Visual Basic Components
XML
C ++/ATL Component Building
Useit.com: Web usability
ASP style
ASP Best Practices, George Reilly is
ASP Quick Lessons, Charles Carroll is
Planning for Asp, John Meade is
asp guidelits, JD Meier
xml
in Side XML Performance, Chris Lovett is
Inside MSXML3 Performance, Chris Lovett