How to improve performance in SQL Server table wit

2019-04-08 04:44发布

问题:

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.

回答1:

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?



回答2:

First of all - don't ever do a SELECT * in production code - reporting or not.

You have three basic choices:

  • move that blob field out into a separate table if it's not always needed; probably not practical since you mention you cannot change the schema

  • be more careful with your SELECT statements to select only those fields that you really need - and omit the blob field

  • see if you can limit your query to include a WHERE clause and find a way to optimize the query plan by e.g. adding a suitable index to the table (if you can)

There's no magic "make this faster" switch - but you can optimize your query or optimize your table layout. Both help. If you can't change anything - neither the table layout, nor add an index, nor change the queries, you'll have a hard time optimizing anything, I'm afraid....

Just changing the field to VARBINARY(MAX) won't change anything at all - no performance improvement to be expected just from changing the data type.



回答3:

A short answer is to only do SELECTs against multiple rows when the fields returned do not include the offending image field, ie no SELECT *. If you want the value of the image field, retrieve it on a case-by-case basis.



回答4:

Setting the large value types out of row option should definitely help performance. The row size will be significantly smaller, SQL Server can do a lot fewer physical reads to get throught the table.