You can optimize your ColdFusion application in many ways. Much of optimizing ColdFusion involves good development and coding practices. For example, good database design and usage is a prime contributor to efficient ColdFusion applications.
In several places, this book documents optimization techniques as part of the discussion of the related ColdFusion topic. This section provides information about general ColdFusion optimization tools and strategies, and particularly about using CFML caching tags for optimization. This section also contains information on optimizing database use, an important area for application optimization.
The ColdFusion MX Administrator provides caching options for ColdFusion pages and SQL queries. For information on these options, see the Administrator online Help and Administering ColdFusion MX.
For information on debugging techniques that can help you identify slow pages, see Chapter 18, "Debugging and Troubleshooting Applications".
For additional information on optimizing ColdFusion, see the Macromedia ColdFusion support center at http://www.macromedia.com/support/coldfusion.
Some ColdFusion pages produce output that changes infrequently. For example, you might have an application that extracts a vendor list from a database or produces a quarterly results summary. Normally, when ColdFusion gets a request for a page in the application, it does all the business logic and display processing required to produce the report or generate and display the list. If the results change infrequently, this can be an inefficient use of processor resources and bandwidth.
The cfcache
tag tells ColdFusion to cache the HTML that results from processing a page request in a temporary file on the server. This HTML does not need to be generated each time the page is requested. When ColdFusion gets a request for a cached ColdFusion page, it retrieves the pregenerated HTML page without having to process the ColdFusion page. ColdFusion can also cache the page on the client. If the client browser has its own cached copy of the page from a previous viewing, ColdFusion instructs the browser to use the client's page rather than resending the page.
Note: The cfcache
tag caching mechanism considers each URL to be a separate page. Therefore, http://www.mySite.com/view.cfm?id=1 and http://www.mySite.com/view.cfm?id=2 result in two separate cached pages. Because ColdFusion caches a separate page for each unique set of URL parameters, the caching mechanism accommodates pages for which different parameters result in different output.
You tell ColdFusion to cache the page results by putting a cfcache
tag on your ColdFusion page above code that outputs text. The tag lets you specify the following information:
action
attribute in the cfcache
tag to ClientCache
.
cfcache
tag flush
action from inappropriately flushing more than one application's caches at a time.You can also specify several attributes for accessing a cached page on the web server, including a user name and password (if required by the web server), the port, and the protocol (HTTP or HTTPS) to use to access the page.
Place the cfcache
tag above any code on your page that generates output, typically at the top of the page body. For example, the following tag tells ColdFusion to cache the page on both the client and the server. On the server, the page is cached in the e:/temp/page_cache directory. ColdFusion retains the cached page for one day.
<cfcache timespan="#CreateTimespan(1, 0, 0, 0)#" directory="e:/temp/page_cache">
Caution: If your Application.cfm page displays text; for example, if it includes a header page, use the cfcache
tag on the Application.cfm page in addition to the pages that you cache. Otherwise, ColdFusion displays the Application.cfm page output twice on each cached page.
ColdFusion automatically flushes any cached page if you change the code on the page. It also automatically flushes pages after the expiration timespan passes.
You can use the cfcache
tag with the action="flush"
attribute to immediately flush one or more cached pages. You can optionally specify the directory that contains the cached pages to be flushed and a URL pattern that identifies the pages to flush. If you do not specify a URL pattern, all pages in the directory are flushed. The URL pattern can include asterisk (*) wildcards to specify parts of the URL that can vary.
When you use the cfcache
tag to flush cached pages, ColdFusion deletes the pages cached on the server. If a flushed page is cached on the client system, it is deleted, and a new copy gets cached, the next time the client tries to access the ColdFusion page.
The following example flushes all the pages in the e:/temp/page_cache/monthly directory that start with HR:
<cfcache action="flush" directory="e:/temp/page_cache/monthly" expirURL="HR*">
If you have a ColdFusion page that updates data you use in cached pages, the page that does the updating includes a cfcache
tag that flushes all pages that use the data.
For more information on the cfcache
tag, see CFML Reference.
In some cases, your ColdFusion page might contain a combination of dynamic information that ColdFusion must generate each time it displays the page, and parts it generates dynamically, but that change less frequently. In this case, you cannot use the cfcache
tag to cache the entire page. Instead, use the cfsavecontent
tag to cache the infrequently changed content.
The cfsavecontent
tag saves the results of processing the tag body in a variable. For example, if the body of the cfsavecontent
tag contains a cfexecute
tag that runs an executable program that displays data, the variable saves the output.
You can use the cfsavecontent
tag to cache infrequently changing output in a shared scope variable. If the information is used throughout the application, save the output in the Application scope. If the information is client-specific, use the Session scope. Because of the overhead of locking shared scope variables, use this technique only if the processing overhead of generating the output is substantial.
Before you use this technique, also consider whether other techniques are more appropriate. For example, query caching eliminates the need to repeat a common query. However, if the effort of processing the data or in formatting the output is substantial, using the cfsavecontent
tag can save processing time.
Using this technique, if the variable exists, the page uses the cached output. If the variable does not exist, the page gets the data, generates the output, and saves the results to the shared scope variable.
The following example shows this technique. It has two parts. The first part welcomes the user and prints out a random lucky number. This part runs and produces a different number each time a user opens the page. The second part performs a database query to get information that changes infrequently, in this case a listing of the current special sale items. It uses the cfsavecontent
tag to get the data only when needed.
Tip: If you use this technique frequently, consider incorporating it in a custom CFML tag.
<!--- Greet the user --->
<cfoutput> Welcome to our home page.<br> The time is #TimeFormat(Now())#.<br> Your lucky number is: #RandRange(1,1000)#<br> <hr><br> </cfoutput> <!--- Set a flag to indicate whether the Application scope variable exists ---> <cflock scope="application" timeout="20" type="readonly"> <cfset IsCached = Not IsDefined("Application.ProductCache")> </cflock> <!--- If the flag is false, query the DB, and save an image of the results output to a variable ---> <cfif not IsCached> <cfsavecontent variable="ProductCache"> <!--- Perform database query ---> <cfquery dataSource="ProductInfo" name="specialQuery"> SELECT ItemName, Item_link, Description, BasePrice FROM SaleProducts </cfquery> <!--- Calculate sale price and display the results ---> <h2>Check out the following specials</h2> <table> <cfoutput query="specialQuery"> <cfset salePrice= BasePrice * .8> <tr> <td>#ItemNAme#</td> <td>#Item_Link#</td> <td>#Description#</td> <td>#salePrice#</td> </tr> </cfoutput> </table> </cfsavecontent> <!--- Save the results in the Applicaiton scope ---> <cflock scope="Application" type="Exclusive" timeout=30> <cfset Application.productCache = ProductCache> </cflock> </cfif> <!--- Use the Application scope variable to display the sale items ---> <cflock scope="application" timeout="20" type="readonly"> <cfoutput>#Application.ProductCache#</cfoutput> </cflock>
The following table describes the code and its function:
Two important ColdFusion MX tools for optimizing your use of databases are the cfstoredproc
tag and the cfquery
tag cachedWithin
attribute.
Note: Poor database design and incorrect or inefficient use of the database are among the most common causes of inefficient applications. Consider the different methods that are available for using databases and information from databases when you design your application. For example, if you need to average the price of a number of products from an SQL query, it is more efficient to use SQL to get the average than to use a loop in ColdFusion.
The cfstoredproc
tag lets ColdFusion MX use stored procedures in you database management system. A stored procedure is a sequence of SQL statements that is assigned a name, compiled, and stored in the database system. Stored procedures can encapsulate programming logic in SQL statements, and database systems are optimized to execute stored procedures efficiently. As a result, stored procedures are faster than cfquery
tags.
You use the cfprocparam
tag to send parameters to the stored procedure, and the cfproresult
tag to get the record sets that the stored procedure returns.
The following example executes a Sybase stored procedure that returns three result sets, two of which the example uses. The stored procedure returns the status code and one output parameter, which the example displays.
<!--- cfstoredproc tag --->
<cfstoredproc procedure = "foo_proc" dataSource = "MY_SYBASE_TEST" username = "sa" password = "" returnCode = "Yes"> <!--- cfprocresult tags ---> <cfprocresult name = RS1> <cfprocresult name = RS3 resultSet = 3> <!--- cfprocparam tags ---> <cfprocparam type = "IN" CFSQLType = CF_SQL_INTEGER value = "1" dbVarName = @param1> <cfprocparam type = "OUT" CFSQLType = CF_SQL_DATE variable = FOO dbVarName = @param2> <!--- Close the cfstoredproc tag ---> </cfstoredproc> <cfoutput> The output param value: '#foo#'<br> </cfoutput> <h3>The Results Information</h3> <cfoutput query = RS1> #name#,#DATE_COL#<br> </cfoutput> <br> <cfoutput> <hr> Record Count: #RS1.recordCount#<br> Columns: #RS1.columnList#<br> <hr> </cfoutput> <cfoutput query = RS3> #col1#,#col2#,#col3#<br> </cfoutput> <br> <cfoutput> <hr><br> Record Count: #RS3.recordCount#<br> Columns: #RS3.columnList#<br> <hr> The return code for the stored procedure is: '#cfstoredproc.statusCode#'<br> </cfoutput>
The following table describes the code and its function:
For more information on creating stored procedures, see your database management software documentation. For more information on using the cfstoredproc
tag, see CFML Reference.
The cfquery
tag cachedWithin
attribute tells ColdFusion to save the results of a database query for a specific period of time. This way, ColdFusion accesses the database on the first page request, and does not query the database on further requests until the specified time expires. Using the cachedWithin
attribute can significantly limit the overhead of accessing databases that do not change rapidly.
This technique is useful if the database contents only change at specific, known, times. or if the database does not change frequently and the purpose of the query does not require absolutely up to date results
You must use the CreateTimeSpan
function to specify the cachedWithin
attribute value (in days, hours, minutes, seconds format). For example, the following code caches the results of getting the contents of the Employees table of the CompanyInfo data source for one hour.
<cfquery datasource="CompanyInfo" name="master" cachedWithin=#CreateTimeSpan(0,1,0,0)#> SELECT * FROM Employees </cfquery>
If an application might take a while to process data, it is useful to provide visual feedback to indicate that something is happening so the user does not assume that there is a problem and request the page again. Although doing this does not optimize your application's processing efficiency, it does make the application appear more responsive.
You can use the cfflush
tag to return partial data to a user, as shown in Chapter 26, "Retrieving and Formatting Data".
You can also use the cfflush
tag to create a progress bar. For information on this technique, see the technical article "Understanding Progress Meters in ColdFusion 5" at http://www.macromedia.com/v1/handlers/index.cfm?id=21216&method=full. (Although this article was written for ColdFusion 5, it also applies to ColdFusion MX.)