[thelist] Response.Write versus varHTML = varHTML & "..."
Anthony Baratta
Anthony at Baratta.com
Fri Jan 11 01:52:37 CST 2002
<longish hopefully not too rambling musing. Note: Win2K with SQL 7 and IIS 5.0>
I've just had a massive paradigm shift. One of those moments where the
whole world just flips upside down.
Over the years I've developed a style of coding in ASP that I had come to
rely on and helped me tackle problems. That is until I found out today that
a major style of coding I was using is significantly "flawed". My
philosophy had been put the branching logic at the top of the page, the
html in the middle (with drop-ins for variables and 'chunks' of HTML) and
the functions called by the branching logic at the bottom of the page (or
if necessary in a shared library). This way I could calculate up front and
then scatter bomb the HTML as necessary with the data collected or mangled.
e.g.
[%
IF THEN END IF
IF THEN END IF
SELECT CASE blah
CASE One
ChunkofHTML = FunctionOne()
CASE Two
ChunkofHTML = FunctionTwo()
CASE Three
ChunkofHTML = FunctionThree()
CASE ELSE Four
ChunkofHTML = FunctionFour()
END SELECT
IF THEN END IF
%]
[HTML]
..blah blah blah...
[%VariableHere%]
..blah blah blah...
[%=ChunkofHTML %]
..blah blah blah...
[%VariableThere%]
..blah blah blah...
[/HTML]
[%
FunctionOne()
FunctionOne = ..blah blah blah...
End Function
FunctionTwo()
FunctionTwo = ..blah blah blah...
End Function
FunctionThree()
FunctionThree = ..blah blah blah...
End Function
FunctionFour()
FunctionFour = ..blah blah blah...
End Function
%]
As I said this process worked great for me, until today. We are designing a
nifty little tool that can (at times) pull up quite a large number of rows
of data to be thrown to the screen. The above system works great when there
are about 50-75 rows of data. However the page becomes unbearably slow
(long processing time server side, watching with Task Manager and the
server bouncing above 80% most of the time) when the number of rows gets
over 100-150.
We did quite a bit of testing and it was not our DB connection and queries.
We have a semi-optimized our queries. We have semi-optimized the database
with indexes and data manglement such that a combination of 11 separate
queries (each with several joins) pulling a cumulative of 1K rows of data
from 2.2 Million records only takes about 5 seconds. (There is probably
room for improvement here but this showed us that the DB and queries were
not the bottleneck, for now.)
Plus Task/Performance Manager showed that DLLHost was consuming most of the
CPU versus SQLServer.
So we looked at the ASP code itself.
To my horror, the following lines (and their numerous kin) proved to be the
performance killer:
Top of Some Loop
subPageHTML = subPageHTML & "...blah blah blah"
subPageHTML = subPageHTML & "...blah blah blah"
subPageHTML = subPageHTML & "...blah blah blah"
Bottom of Some Loop
It didn't make any difference how I pulled the data from the DB, either
iterating over the rows with the Record Set open, or pulling the rows via
getRows and iterating over the returned array. Timing data inserted into
the script showed that over an 8 second period the above process proceeded
to slow to a crawl very quickly.
e.g. First Second - Processed 115 Lines
Second Second - Processed 87 Lines
Third Second - Processed 55 Lines
Fourth Second - Processed 27 Lines
Fifth Second - Processed 17 Lines
Sixth Second - Processed 17 Lines
Seventh Second - Processed 17 Lines
Eighth Second - Processed 17 Lines
Granted there was some over head processing due to the Timing Data, but
this reflected very well the performance slow down we were seeing with real
data as the rows returned increased.
It was obvious that the subPageHTML = subPageHTML & "" lines were killing
performance. So I proceeded to hack up my ASP page and move code around. I
had to push 90% of the logic/branching code to the "center" of the page in
order to output the data in the correct location (replacing the Functions
with Subs). If I was to replace the subPageHTML = subPageHTML & "" process
with response.write & response.flush, then I needed to get the lines of
code that called the former functions now subroutings to the location where
I wanted the output.
So now I had this:
[%
IF THEN END IF
IF THEN END IF
%]
[HTML]
..blah blah blah...
[%VariableHere%]
..blah blah blah...
[%
SELECT CASE blah
CASE One
SubOne()
CASE Two
SubTwo()
CASE Three
SubThree()
CASE ELSE Four
SubFour()
END SELECT
IF THEN END IF
%]
..blah blah blah...
[%VariableThere%]
..blah blah blah...
[/HTML]
[%
SubOne()
Response.Write ..blah blah blah...
Response.Flush
End Sub
SubTwo()
Response.Write ..blah blah blah...
Response.Flush
End Sub
SubThree()
Response.Write ..blah blah blah...
Response.Flush
End Sub
SubFour()
Response.Write ..blah blah blah...
Response.Flush
End Sub
%]
This of course completely threw off variables within the HTML that expected
to have data higher up in the page. And creates a quandary; How do you
organize the HTML and code when you are forced to throw data to the browser
when it's created?
e.g. You want to toss a Message to the user near the top of the page of how
many rows returned. But the row counter and HTML created from the DB data
are now being calculated and outputted "after" that area of the page has
already been sent off to the browser. It forces you to go to the DB more
often than you were previously planning and break up functions that IMvHO
should be related blocks of code since they share the same source of data
or related logic. Granted, based upon the speed increase this extra trip
does not subtract from the performance greatly - but it feels so unclean.
I even tried SpeedString (
http://www.intesoft.co.uk/speedstring/default.asp ) from InteSoft, but did
not see the performance increase that we saw by moving to Response.Writes.
With the above changes the processing time dropped to 2 seconds.
<digress>In fact, Netscape 6.2 appears to have a huge rendering problem
with a set of three nested tables. The rendering time with Netscape is
much, much longer than the time to calculate and send the data to the
browser. The first two are framing for the third. The third table is the
biggest, holding all the rows of data being returned. IE 5.x and 6.x have
no problem rendering the output. Go figure. (I'll be testing with the
latest Mozilla release tomorrow.)</digress>
So tomorrow I tackle my now fractured ASP world. As much as I hate to work
with VBS (the ultimate brain dead language), this really really irks me.
For those that have read this far and are not laughing their arses off at
my woes - any perls of wisdom outside of "drop ASP for solution XYZ"?
---
Anthony Baratta
President
Keyboard Jockeys
"Conformity is the refuge of the unimaginative."
More information about the thelist
mailing list