views:

83

answers:

4

I have the following situation:

  • .net 3.5 WinForm client app accessing SQL Server 2008
  • Some queries returning relatively big amount of data are used quite often by a form
  • Users are using local SQL Express and restarting their machines at least daily
  • Other users are working remotely over slow network connections

The problem is that after a restart, the first time users open this form the queries are extremely slow and take more or less 15s on a fast machine to execute. Afterwards the same queries take only 3s. Of course this comes from the fact that no data is cached and must be loaded from disk first.

My question:
Would it be possible to force the loading of the required data in advance into SQL Server cache?

Note
My first idea was to execute the queries in a background worker when the application starts, so that when the user starts the form the queries will already be cached and execute fast directly. I however don't want to load the result of the queries over to the client as some users are working remotely or have otherwise slow networks.
So I thought just executing the queries from a stored procedure and putting the results into temporary tables so that nothing would be returned.
Turned out that some of the result sets are using dynamic columns so I couldn't create the corresponding temp tables and thus this isn't a solution.

Do you happen to have any other idea?

+3  A: 

Are you sure this is the execution plan being created, or is it server memory caching that's going on? Maybe the first query loads quite a bit of data, but subsequent queries can use the already-cached data, and so run much quicker. I've never seen an execution plan take more than a second to generate, so I'd suspect the plan itself isn't the cause.

Have you tried running the index tuning wizard on your query? If it is the plan that's causing problems, maybe some statistics or an additional index will help you out, and the optimizer is pretty good at recommending things.

rwmnau
You're right (+1), I've corrected my question. There is a lot of data involved and the slowness surely comes from the fact that it must be loaded from disk first. It's not the plan, additional index has already been added. It really is about the caching.
Marc
+1 this is far more likely to be data caching than query plan creation. You could run EXPLAIN on the query in the query browser to satisfy yourself this is the case. Is the DB connection also opened at the point this form is opened (another potential slow down)?
Paolo
@Marc: It may be possible to put the queries into a stored procedure and then have it kicked off asynchronously - see http://nayyeri.net/asynchronous-command-execution-in-net-2-0. This way, you can start the SP when the application loads, have it pull everything off disk and into the cache, and the application continues on in the meantime.
rwmnau
+1  A: 

I'm not sure how you are executing your queries, but you could do:

SqlCommand Command = /* your command */
Command.ExecuteReader(CommandBehavior.SchemaOnly).Dispose();

Executing your command with the schema-only command behavior will add SET FMTONLY ON to the query and cause SQL Server to get metadata about the result set (requiring generation of the plan), but will not actually execute the command.

Michael Petito
I've tested it but it didn't help at all. The problem really is about caching the data from disk. Setting FMTONLY on won't actually run the query so no data is cached at all. Thanks anyway for the idea.
Marc
A: 

To narrow down the source of the problem you can always use the SQL Server Objects in perfmon to get a general idea of how the local instance of SQL Server Express is performing.

In this case you would most likely see a lower Buffer Cache Hit Ratio on the first request and a higher number on subsequent requests.

Also you may want to check out http://msdn.microsoft.com/en-us/library/ms191129.aspx It describes how you can set a sproc to run automatically when the SQL Server service starts up. If you retrieve the Data you need with that sproc then maybe the data will remain cached and improve the performance the first time the data is retrieved by the end user via your form.

TooFat
A: 

In the end I still used the approach I tried first: Executing the queries from a stored procedure and putting the results into temporary tables so that nothing would be returned. This 'caching' stored procedure is executed in the background whenever the application starts.
It just took some time to write the temporary tables as the result sets are dynamic.

Thanks to all of you for your really fast help on the issue!

Marc