Storing objects in Session Variables - exactly why not?

M

mjkahn

I've read (and read!) that you shouldn't store objects in Session variables.
I've read these reasons:

- The object takes up memory that may not be freed until the session times
out. Better to create the object only when you actually use it.

- Causes poor performance because the thread that created the object has to
service all requests for it.

Assuming I can live with the memory and performance implications (a big if,
but let's assume it for a minute), what other reasons are there?

MJ.
 
J

Jason Brown [MSFT]

The reasons against this diminish as server power grows - obviously if you
have a really hefty server, you can handle the memory usage issues. THe
threading issue is fairly easily overcome by making sure you only use free
threaded objects (such as MSXML.FreeThreadedDomDocument).

It can get to be a bit of a chore to manage them too, and debugging can be
tricky, but if you think you can handle that, along with the memory
requirements, then feel free. Just make sure you have an idea of how much
memory you're going to end up using.
 
T

Thomas

i'm using ADO objects in Session and Application memory for over 3 years now
without any problems at all. having a shared pool of ADO.Connection objects
that is assigned to new clients through global.asa proofed to be much faster
than allocate and instantiate the objects at runtime.

threading issue i haven't noticed, although we have quite a few conqurrent
users on all the time, server cpu load is <6% avr (3ghz system).

of course memory usage is very high, the web's application pool uses around
1 - 1.5gb. but hey, memory is cheap nowadays ;-)

- thomas
 
B

Bob Barrows [MVP]

Thomas said:
i'm using ADO objects in Session and Application memory for over 3
years now without any problems at all. having a shared pool of
ADO.Connection objects that is assigned to new clients through
global.asa proofed to be much faster than allocate and instantiate
the objects at runtime.

And exactly how did you determine this?
threading issue i haven't noticed, although we have quite a few
conqurrent users on all the time, server cpu load is <6% avr (3ghz
system).
of course memory usage is very high, the web's application pool uses
around 1 - 1.5gb. but hey, memory is cheap nowadays ;-)

By doing this, you've prevented the use of OLE DB session pooling, and, if
you haven't changed the threading model of ADO from apartment to
free-threaded (which you should not do if using Jet), you've serialized all
of your database access.

Just because you cannot perceive a performance issue does not mean one does
not exist.

Bob Barrows
 
T

Thomas

And exactly how did you determine this?

http://www.microsoft.com/downloads/...5A-062A-439E-A67D-75A89AA36495&displaylang=en

Just because you cannot perceive a performance issue does not mean one
does not exist.

just because you assume i didn't knew about the serialized execution problem
does not mean i didn't knew ;-)

see, the connections are assigned from a pool of connections. of course
you're right: if 2 users receive the same object, their fired sql code will
be serialized. easy workaround: every user receives a different connection
object. add some logic (i.e. if a user opens 2 browsers and creates thus 2
sessions, assign him only 1 connection) and you're set. counter variables
measure if a shared connection object is still in use, if not it is
destroyed after session end.
of course, it needs some programming and session startup is slower than
without. but the gained speed afterwards make this worth.

this works pretty neat and faster than any other solution i came across so
far. it works fine even with ~900 concurrent user sessions (with 20min
timeout). i'm open to even better suggestions, tho...

- thomas
 
B

Bob Barrows [MVP]

Thomas said:

Microsoft has published results of stress tests indicating the opposite of
what you say your results are. I suspect you were not actually taking
adbantage of session pooling when you ran your tests, but of course, this is
only a suspicion.
far. it works fine even with ~900 concurrent user sessions (with 20min
timeout). i'm open to even better suggestions, tho...

The best suggestion I have is the one that comes from Microsoft: take
advantage of session pooling by instantiating and opening connections on
each page, closing them as soon as you are finished using them. Only the
first opening of a connection will take time. Once the connection is in the
pool, subsequent uses will not require the same time to open them.

By taking advantage of session pooling, you minimize the number of
connections to your database. Don't forget: each connection uses memory on
the database server as well as the web server (assuming you are using a
server-based dbms, which you must be with 900 concurrent users).

Here's more information:
http://msdn.microsoft.com/library/en-us/dnmdac/html/pooling2.asp
http://support.microsoft.com/?scid=kb;en-us;Q176056
http://support.microsoft.com/default.aspx?scid=kb;en-us;191572
http://support.microsoft.com/default.aspx?scid=kb;en-us;324686

connection failures caused by pooling disablement
http://support.microsoft.com/default.aspx?scid=kb;en-us;328476

implicit connections:
http://support.microsoft.com/?kbid=271128

Bob Barrows
 
T

Thomas

Microsoft has published results of stress tests indicating the opposite of
what you say your results are. I suspect you were not actually taking
adbantage of session pooling when you ran your tests, but of course, this
is only a suspicion.

hmm thats interesting.

wouldn't be OLE DB connections pooled when using default settings? i ran the
tests ~3 years ago on IIS5 with connection code similar to the one below -
but of course with many different pages with different (more expensive)
queries and multiple requests.

-----------------------------------------
connection opens on each page:

FILE: TEST_NOSESSION.ASP:
<% Option Explicit

Const adOpenForwardOnly = 0

Dim oConn, rsRecords, sOutput
Set oConn = Server.CreateObject("ADODB.Connection")
oConn.open
"provider=SQLOLEDB;server=localhost;uid=webuser;pwd=test123;database=movies;QuotedID=No"

Set rsRecords = Server.CreateObject("ADODB.Recordset")
rsRecords.Open "SELECT movies.mov_name FROM movies WHERE mov_id > 100",
oConn, adOpenForwardOnly

Do Until rsRecords.EOF
sOutput = sOutput & "<br>" & rsRecords("mov_name")
rsRecords.MoveNext
Loop
rsRecords.close
response.write sOutput

oConn.close

set rsRecords = nothing
set oConn = nothing

%>

---------------------------------------------
connection opened in global.asa:

FILE GLOBAL.ASA: (simplified)
<%
Sub Session_OnStart()
Call ConnectDB()
End Sub

Sub Session_OnEnd()
' some stuff here as well
End Sub

Function ConnectDB()
If (check here if for this user a Connection object already exists)
= false then
' new connection
Set Application("DB_xxx") =
Server.CreateObject("ADODB.Connection")
Application("DB_xxx").open
"provider=SQLOLEDB;server=localhost;uid=webuser;pwd=test123;database=movies;QuotedID=No"
End If

Set Session("DB") = Application("DB_xxx")
End Function
%>

FILE: TEST_WITHSESSION.ASP:
<% Option Explicit

Const adOpenForwardOnly = 0

Dim rsRecords, sOutput

Set rsRecords = Server.CreateObject("ADODB.Recordset")
rsRecords.Open "SELECT movies.mov_name FROM movies WHERE mov_id > 100",
Session("DB"), adOpenForwardOnly

Do Until rsRecords.EOF
sOutput = sOutput & "<br>" & rsRecords("mov_name")
rsRecords.MoveNext
Loop
rsRecords.close
response.write sOutput

set rsRecords = nothing
%>

The best suggestion I have is the one that comes from Microsoft: take
advantage of session pooling by instantiating and opening connections on
each page, closing them as soon as you are finished using them. Only the
first opening of a connection will take time. Once the connection is in
the pool, subsequent uses will not require the same time to open them.

what about the Server.CreateObject? i always thought object creation and
instantiation would add heavy overhead... and thus negatively affect
performance
By taking advantage of session pooling, you minimize the number of
connections to your database. Don't forget: each connection uses memory on
the database server as well as the web server (assuming you are using a
server-based dbms, which you must be with 900 concurrent users).

thats true. the db shows quite a lot of connections. but because of the 900
concurrent users are not all firing queries at the same time, the db is not
overloaded. of course the memory requirements are quite huge, db + web uses
around 2.5gb of memmory :)

interesting lecture for a boring sunday... erhm wait, its easter!

thanks for your input and happy easter from switzerland!

- thomas
 
B

Bob Barrows [MVP]

Thomas said:
hmm thats interesting.
wouldn't be OLE DB connections pooled when using default settings?

Yes, in IIS, session pooling is on by default (which can be confirmed by
reading the material in the links I provided). However, there are coding
practices that will cause it to be disabled. A quick perusal of your code
does not reveal any of the practices i was thinking of.

<snip>

Thanks for the code. I will try it myself sometime.
Can you share the results of your tests? How much of a difference was
achieved by using the Session-bound object?

PS. Have you at least changed the threading model of your ADO objects by
using the makfre15.bat batch file which can be found in your ADO folder? If
you are not using Jet, you really should do this. Most of my objections to
caching the object in session go away if you change the treading model.
what about the Server.CreateObject? i always thought object creation
and instantiation would add heavy overhead... and thus negatively affect
performance

In earlier versions of IIS, it was always recommended that you get MTS
involved by using Server.CreateObject. In later versions (5.1 and higher, I
think) the reasons for encouraging the use of server.createobject have been
resolved. Performance can be improved by using the vbscript version of
CreateObject (simply leave out the "Server.")

Would it be too much to ask for you to repeat your tests using CreateObject
instead of Server.CreateObject?
thats true. the db shows quite a lot of connections. but because of
the 900 concurrent users are not all firing queries at the same time, the
db
is not overloaded. of course the memory requirements are quite huge, db +
web uses around 2.5gb of memmory :)
Not only that, but you also may be violating your license agreement for your
database server. But I am not a lawyer. Just providing some food for
thought.

Have a good Easter,
Bob Barrows
 
T

Thomas

Thanks for the code. I will try it myself sometime.
Can you share the results of your tests? How much of a difference was
achieved by using the Session-bound object?

it was roughly in the regions of 20% performance gain. i will defenitely
redo my tests in the near future. the configuration has changed (iis6,
windows2003, new server, new ado). also from what i read here and in your
links, my solution might not be faster anymore in the current environement.
if i can get rid of manual pooling without performance-loss, i'll do this
happily - especially as this would free up ressources.
PS. Have you at least changed the threading model of your ADO objects by
using the makfre15.bat batch file which can be found in your ADO folder?
If you are not using Jet, you really should do this. Most of my objections
to caching the object in session go away if you change the treading model.

nope. i don't even have this batch file... maybe because in windows2003 mdac
2.8 is already included?
Would it be too much to ask for you to repeat your tests using
CreateObject instead of Server.CreateObject?

not at all. i'll prepare some new tests. i always thought it
Server.CreateObject was recommended over CreateObject
Not only that, but you also may be violating your license agreement for
your database server. But I am not a lawyer. Just providing some food for
thought.

honestly, i never clearly understood the licencing of the db server. the
seller sold us a 5-client license of ms-sql server standard. still, does a
5-client-license mean
- 5 different machines connecting to the db-server? - there's only 1 machine
in my setup
- 5 different db-login connecting at the same time to the db-server? - all
my users use the same login
- 5 different connections? - hopefully not. even when you open up the
administration manager, you get more than these numbers of connections...
:)

cheers,
thomas
 
B

Bob Barrows [MVP]

Thomas said:
it was roughly in the regions of 20% performance gain. i will
defenitely redo my tests in the near future. the configuration has
changed (iis6, windows2003, new server, new ado). also from what i
read here and in your links, my solution might not be faster anymore
in the current environement. if i can get rid of manual pooling
without performance-loss, i'll do this happily - especially as this
would free up ressources.

nope. i don't even have this batch file... maybe because in
windows2003 mdac 2.8 is already included?

Interesting. I do not see it on one of our W2003 servers either. Several
possibilities come to mind:

1. It's no longer necessary to do this change in W2003
2. They don't want you doing this change in W2003
3. You can't make this change in W2003

I'm not sure which is the correct reason.

All the batch file does is run the registry merge file called ADOFRE15.REG
(contained in the same folder) that contains these registry keys:

REGEDIT4

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{00000507-0000-0010-8000-00AA006D2EA4}\InprocServer32]
"ThreadingModel"="Both"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{00000514-0000-0010-8000-00AA006D2EA4}\InprocServer32]
"ThreadingModel"="Both"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{0000050B-0000-0010-8000-00AA006D2EA4}\InprocServer32]
"ThreadingModel"="Both"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{00000535-0000-0010-8000-00AA006D2EA4}\InprocServer32]
"ThreadingModel"="Both"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{00000541-0000-0010-8000-00AA006D2EA4}\InprocServer32]
"ThreadingModel"="Both"

I don't have access to the registries on our W2003 servers right now so I
can't investigate more thoroughly.

not at all. i'll prepare some new tests. i always thought it
Server.CreateObject was recommended over CreateObject

As did I. I recently had it pointed out to me that things had changed.

Bob Barrows
 
T

Thomas

1. It's no longer necessary to do this change in W2003

all the registry keys are set to ThreadingModel = Apartment
2. They don't want you doing this change in W2003
3. You can't make this change in W2003

well. "never change a running system". so i'm resisting in playing around
for the moment and...
As did I. I recently had it pointed out to me that things had changed.

.... rather change my code for the better :)

thanks,
thomas
 
T

Thomas

ok, here's the deal:

it really is faster to use the existing adodb pooling. while allocating /
connecting the ADODB.Connection object costs quite some time, the advantage
of not having ~300 sleeping connections to the db server overweights this.
and using CreateObject instead of Server.CreateObject improves object
allocation time as well.

and last but not least: not having to deal with pooling myself makes the
code slicker and nicer.

while my system was faster for an iis4/asp2 setup on w2k (where initial
tests where made some years ago), it is defenitely not faster anymore on
iis6/asp3/w2k3.

thanks for doubting my initial postings. while storing objects in
session/application does not seem to be any problem, having a multitude of
open connections to the sql server really is.

unfortunately, due do a wrongly licenced db (thanks for pointing this one
out as well - #@%& sales people who sold us this licence), we will have to
switch the db servers in the very near future. but i hope the newly aquired
findings are also applicable in the new system.

cheers,
thomas
 
B

Bob Barrows [MVP]

Thomas said:
ok, here's the deal:

it really is faster to use the existing adodb pooling. while
Thanks. It's always good to see the assumptions based on theory confirmed.

Bob Barrows
 
M

Mark Schupp

regarding the db switch
will it really be cheaper to switch to a different dbms (your time has to
have a value also)?
 
T

Thomas

defenitely. its a NPO and my work is [most unfortunately ;-)] not paid at
all in either ways. this is also the reason why we cannot afford buying
another license.

we've choosen postgresql 8.0.1 now, which not only covers all the features
we used in mssql (we aren't using any fancy stuff like replication) but also
performs surprisingly great. i will dearly miss the msssql admin console
tho...

the mssql will now be "downgraded" do be our mailserver's db-backend, which
is - after some investigation - in perfect correspondance with the license
we got.

- thomas
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,775
Messages
2,569,601
Members
45,182
Latest member
alexanderrm

Latest Threads

Top