How to improve performance in SQL Server table with image fields?

Paulo Santos picture Paulo Santos · Feb 12, 2010 · Viewed 15k times · Source

I'm having a very particular performance problem at work!

In the system we're using there's a table that holds information about the current workflow process. One of the fields holds a spreadsheet that contains metadata about the process (don't ask me why!! and NO I CAN'T CHANGE IT!!)

The problem is that this spreadsheet is stored in an IMAGE field in an SQL Server 2005 (within a database set with SQL 2000 compatibility).

This table currently has 22K+ lines and even a simple query like this:

SELECT TOP 100 *
  FROM OFFENDING_TABLE

Takes 30 seconds to retrieve the data in Query Analyser.

I'm thinking about updating the compatibility to SQL 2005 (once that I was informed that the app can handle it).

The second thing I'm thinking is to change the data-type of the column to varbinary(max) but I don't know if doing this will affect the application.

Another thing that I'm considering is to use sp_tableoption to set the large value types out of row to 1 as it's currently 0, but I have no information if doing this will improve performance.

Does anyone know how to improve performance in such scenario?


Edited to clarify

My problem is that I have no control on what the application asks to the SQL Server, and I did some Reflection on it (the app is a .NET 1.1 website) and it uses the offending field for some internal stuff that I have no idea what it is.

I need to improve the overall performance of this table.

Answer

Remus Rusanu picture Remus Rusanu · Feb 12, 2010

I'd recommend you look into the offending table layout health:

select * from sys.dm_db_index_physical_stats(
       db_id(), object_id('offending_table'), null, null, detailed);

Things too look for are avg_fragmentation_in_percent, page_count, avg_page_space_used_in_percent, record_count and ghost_record_count. Cues like high fragmentation, or a high number of ghost records, or a low page used percent indicate problems and things can be improved quite a bit just by rebuilding the index (ie. the table) from scratch:

ALTER INDEX ALL ON offending_table REBUILD;

I'm saying this considering that you cannot change the table nor the app. If you'd be able to change the table and the app, the advice you already got is good advice (don't use '*', dont' select w/o a condition, use the newer varbinary(max) type etc etc).

I'd also look into the average page lifetime in performance counters to understand if the system is memory starved. From your description of the symptomps the system looks IO bound which leads me to think there is little page caching going on, and more RAM could help, as well as a faster IO subsytem. On a SQL 2008 system I would also suggest turning page compression on, but on 2005 you can't.
And, just to be sure, make sure the queries are not blocked by contention from the app itself, ie. the query doesn't spend 90% of that 30 seconds waiting for a row lock. Look at sys.dm_exec_requests while the query is running, see the wait_time, wait_type and wait_resource. Is it PAGEIOLATCH_XX? Or is it a lock? Also, how is the sys.dm_os_wait_stats in your server, what are the top wait reasons?