<!--- The first optimization is to combine the two queries (orders and order items) into one query. This will make the following CFLoop a bit more complicated but will only require going to the database once vs. N-times where N is the number of the orders. I am ONLY using SELECT * because I am not sure of the database strucutre. Otherwise, I would NEVER use SELECT * as more often than not, you don't need every column (and for readability reasons). ---> <cfquery name="theOrders" datasource="XXXXXX"> SELECT * FROM <!--- Create the table from the first query. I am doing this for two reasons: 1. I am not sure of the DB structure. 2. We can use a LEFT OUTER Join in this query and still use an INNER join on the next without any sort of confusion. ---> ( SELECT * FROM Orders LEFT OUTER JOIN Loger ON Loger.UserID = Orders.CartID ) AS o INNER JOIN realcart rc ON rc.WebOrderID = o.WebOrderID </cfquery> <!--- Get the name of the temp file that we are going to write our tab delimited data to. ---> <cfset strTempFile = ( ExpandPath( "allOrders" ) & DateFormat( Now(), "yyyy_mm_dd" ) & ".csv" ) /> <!--- Create a string buffer to hold our output. By writing to a string buffer rather than doing CFFile actions for every loop iteration we are going to increase our speed greatly. Writing to the file system is one of the most costly actions you can take in programming. Try to minimize it when possible (within reason). ---> <cfset sbOutput = CreateObject( "java", "java.lang.StringBuffer" ).Init() /> <!--- Start off, instead of writing our column headers to the file system (costly), let's just append them to our string buffer. Notice that we are adding a line break at the end of the data line. This is because there is nothing inherent to the String Buffer about line breaks. In the other method, we were Appending data using CFFile. CFFile adds a new line character by default. ---> <cfset sbOutput.Append( "WebOrderID CartID Accountnumber Shipping SubTotal Total Order-Hold" & Chr( 13 ) & Chr( 10 ) ) /> <!--- Get the initial order ID. We are going to need to keep track of the order ID so that we know when to output a new order row (when that ID changes). To start with, set it to a value we know cannot possibly be valid. ---> <cfset intOrderID = -1 /> <!--- Loop over the order/cart detail query. ---> <cfloop query="theOrders"> <!--- Check to see if we have a new order ID. If we do, then we need to output a mid-header row for this particular order. ---> <cfif (theOrders.WebOrderID NEQ intOrderID)> <!--- Store the order ID so that we don't recreate this mid-header row. ---> <cfset intOrderID = theOrders.WebOrderID /> <!--- Instead of outputing the mid-header row to a file, let's add it to our string buffer. ---> <cfset sbOutput.Append( "#theOrders.WebOrderID# #theOrders.CartID# #theOrders.Accountnumber# #theOrders.Shipping1# #theOrders.Subtotal# #theOrders.Total# #theOrders.Hold#" & Chr( 13 ) & Chr( 10 ) ) /> </cfif> <!--- ASSERT: At this point, we know that we are IN an order detail loop and that our header row has already been taken care of. That means that for the rest of the loop body, all we need to care about are the order details. ---> <cfset sbOutput.Append( "#theOrders.cartID# #theOrders.Vendor# #theOrders.Delivery# #theOrders.Item# #theOrders.ItemNumber# #theOrders.Quantity# #theOrders.Price# #theOrders.Attention#" & Chr( 13 ) & Chr( 10 ) ) /> </cfloop> <!--- Now that we have all of our tab delimited data in the Java StringBuffer, we can write it to the file system. This is a bigger file write that before, but since we are only doing one, rather than ONCE per data row, it will be crazy faster. When writing the string buffer to the file, we have to convert it to a single string using ToString(). ---> <cffile action="WRITE" file="#strTempFile#" output="#sbOutput.ToString()#" />