Giant String Problem
If you’ve ever had a scenario where you’ve had to create strings of massive size, you may have noticed a decline in the performance of your ColdFusion page. I’m not talking hundreds of characters. I’m talking hundreds of thousands of characters. For example if you are assembling a string to be written to file (like .CSV), and your string will end up containing thousands of lines, there is a better way than just concatenating the string in your inner loop. Here is an example of how one may approach this.
-
<cfquery name="getData" datasource="someDataSource">
-
SELECT field1, field2, field3, field4 FROM someTableWithLotsOfData
-
</cfquery>
-
-
<cfset result = "">
-
<cfoutput query="getData">
-
<cfset result = result & "#field1#,#field2#,#field3#,#field4##Chr(13)##Chr(10)#">
-
</cfoutput>
-
-
<cfoutput>#result#</cfoutput>
Now, this is a perfectly reasonable solution. However, once you start getting into the tens of thousands of records, and you have to assemble longer strings with more fields, this method starts to become slow. The reason? The concatenation process is an expression that must first be evaluated, then assigned. So, it must grab the VALUE of result first, then append the new data to it, then assign this NEW string BACK to the variable. For each iteration this gets slower and slower. A better method is presented below. Please note that this works only on ColdFusion MX and up (and I’ve only tested this in MX 7).
-
<cfquery name="getData" datasource="someDataSource">
-
SELECT field1, field2, field3, field4 FROM someTableWithLotsOfData
-
</cfquery>
-
-
<cfset result = createObject("java", "java.lang.StringBuffer").init(2048)>
-
-
<cfoutput query="getData">
-
<cfset result.append("#field1#,#field2#,#field3#,#field4##Chr(13)##Chr(10)#")>
-
</cfoutput>
-
-
<cfoutput>#result.toString()#</cfoutput>
The way this works is to instantiate an instance of the Java StringBuffer class. The StringBuffer class is designed for high speed string appends and inserts, i.e. string building.
The result.init call basically overrides the default constructor of the class and sets the initial size of the string buffer to 2K. Also, if the object needs more memory, it will allocate additional memory in 2K blocks.