views:

96

answers:

3

Hello, I have the following (simplified) query

select P.peopleID, P.peopleName, ED.DataNumber
from peopleTable P
    left outer join (   
        select PE.peopleID, PE.DataNumber 
        from formElements FE
             inner join peopleExtra PE on PE.ElementID = FE.FormElementID 
        where FE.FormComponentID = 42
    ) ED on ED.peopleID = P.peopleID

Without the sub-query this procedure takes ~7 seconds, but with it, it takes about 3minutes.

Given that table peopleExtra is rather large, is there a more efficient way to do that join (short of restructuring the DB) ?

More details:

The inner part of the sub-query, e.g.

  select PE.peopleID, PE.DataNumber 
        from formElements FE
             inner join peopleExtra PE on PE.ElementID = FE.FormElementID 
        where FE.FormComponentID = 42

Takes between <1 and 5 seconds to execute, and returns 95k rows

There are 1500 entries in the peopleTable.

+1  A: 

how long does that sub-query take to run by itself? If it takes close to 3 minutes, then you need to make the sub-query more effecient on its own - if it takes only a few seconds, then it's the whole statement that needs to be worked on.

Are there any indexes on peopleExtra? Specifically, on that starts with ElementID and includes DataNumber? I suspect the problem is the join inside your subquery that's causing trouble.

Also, can you please include a query plan? Run SET SHOWPLAN_TEXT ON before your query and then post the results here - that will help determine what's slowing it down.

rwmnau
unfortunately the query itself is 130 lines longer than the given example, so I cant include the actual execution plan. It's definitely the sub-query that's the slow bit. I have the indexes specified by Quassnoi.
Zeus
@Zeus: if we are talking about performance you should specify the query exactly as it is. Every of these 130 lines can matter.
Quassnoi
@Quassnoi you may be correct... I have the same join in the original procedure. Without it, the procedure takes a few seconds, with it, it takes minutes. Which is why I attempted to present this simplified example. I was hoping there was something wonky with the join syntax :)
Zeus
+1  A: 

Make a join against the table instead of a subquery, that should give the query preprocessor better freedom to make the best joins.

select p.peopleID, p.peopleName, pe.DataNumber
from peopleTable p
left join (
  formElements fe
  inner join peopleExtra pe on pe.ElementID = fe.FormElementID
) on pe.peopleID = p.peopleID
where fe.FormComponentID = 42
Guffa
This query will filter out the people who has no `FormComponentID = 42`. Besides, `SQL Server`'s optimizer is smart enough to deal with subqueries without rewriting them.
Quassnoi
+1  A: 

Your query is OK, just create the following indexes:

PeopleExtra (PeopleID) INCLUDE (DataNumber, ElementID)
FormElements (FormComponentID, FormElementID)

Rewriting the join is not required (SQL Server's optimizer can deal with the nested queries just fine), though it can make your query more human-readable.

Quassnoi
these indexes are in place, although the previous coder stuck "with recompile" in the procedure. this seems to be the "quick fix" where I work. seems like a code smell if you ask me!
Zeus
I've marked this as correct as it was indeed to do with the optimizer - it turned out it have been optimized incorrectly. reshuffling the rest of the procedure fixed this. unfortunately a bit of a red herring!
Zeus