views:

208

answers:

5

I have a view that uses 11 outer joins and two inner joins to create the data. This results in over 8 million rows. When I do a count (*) on the table it takes about 5 minutes to run. I'm at a loss as to how to improve the performance of this table. Does anyone have any suggestions on where to begin? There appear to be indexes on all of the columns that are joining (though some are composit, not sure if that makes a difference...)

Any help appreciated.

+1  A: 

A few things you could consider:

  1. denormalisation. Reduce the number of joins required by denormalising your data structure
  2. partitioning. Can you partition data from large tables? e.g. a large table, could perform better if partitioned into a number of smaller tables. Enterprise Edition from SQL 2005 onwards has good support for partitioning, see here. Would consider this if you start getting in the realms of 10s/100s of millions of rows
  3. index management/statistics. Are all indexes defragged? Are statistics up to date?
AdaTheDev
+1  A: 

Run the sql profiler/index tuning wizard. sometimes it makes index recommendations that don't immediately make sense, but turn out to have wonderful perf benefits

Joel Martinez
I didn't know Profiler made recommendations. Do you mean Query Analyzer?
Abe Miessler
sorry, the tool that actually does the recommendations is the "Sql Server Index Tuning Wizard". This tool takes as an input a profiler trace file :-)
Joel Martinez
+2  A: 

This is a hard one, with a complex view you also have potential interactions with queries against the view, so guaranteeing reasonable performance will be quite hard. Outer joins in views (especially complex ones) are also prone to cause trouble for the query optimiser.

One option would be to materialise the view (called 'indexed views' on SQL Server). However you may need to monitor update performance to check that it does not impose too much overhead. Also, outer joins in a materialised view may preclude real-time refresh; if you need this then you may have to re-implement the view as a denormalised table and maintain the data with triggers.

Another possibility would be to examine whether the view could be split into two or three simpler views, possibly materialising some but not all of the view. It may be easier to materialise some of the view and get performance from the system that way.

ConcernedOfTunbridgeWells
I had considered creating an indexed view but from what I understand you can't do that on a view that uses any kind of outer join. Am I mistaken on that?
Abe Miessler
That's correct. You might be able to materialize part of the view and then build a view on top of that.. Alternatively you might be able to re-implement the view as a table maintained by a set of triggers.
ConcernedOfTunbridgeWells
Yeah I think this is the approach i'm going to have to take.
Abe Miessler
do you have any idea how much space will this take? making this view persisted is not a good idea.
Mladen Prajdic
+2  A: 

your basic premise is wrong. having a view that returns 8 million rows is not a good idea because realisticaly you can't really do anything with so much data. 5 minutes sounds pretty good for 8 million count() because of all those joins.

what you have to do is to think about your business problem and write a smaller query/view.

Mladen Prajdic
A: 

Maybe some of the tables which you are trying to (outer) join are disjoint? If so, consider creating stored procedure instead of view and create something like this:

select ... into #set1 from T1 left join T2 left join... where ...

select ... into #set2 from T3 left join T4 left join... where ...

...

select ... from #set1 left join #set2 left join ...

With this, you can avoid processing huge amount of data. When you make outer joins, optimizer often cannot move selection down in the parse tree of query (if it done so, you wouldn't get rows with nulls which you probably want)

Of course you cannot create query with joining with stored procedure. This is only basic idea which you can use.

Marcin Krupowicz