Friday, February 4, 2011

Slow SQL Query due to inner and left join?

Can anyone explain this behavior or how to get around it?

If you execute this query:

select * 
from TblA
left join freetexttable ( TblB, *, 'query' ) on TblA.ID = [Key]
inner join DifferentDbCatalog.dbo.TblC on TblA.ID = TblC.TblAID

It will be very very very slow.

If you change that query to use two inner joins instead of a left join, it will be very fast. If you change it to use two left joins instead of an inner join, it will be very fast.

You can observe this same behavior if you use a sql table variable instead of the freetexttable as well.

The performance problem arises any time you have a table variable (or freetexttable) and a table in a different database catalog where one is in an inner join and the other is in a left join.

Does anyone know why this is slow, or how to speed it up?

  • Index the field you use to perform the join.

    A good rule of thumb is to assign an index to any commonly referenced foreign or candidate keys.

  • What you should usually do is turn on the "Show Actual Execution Plan" option and then take a close look at what is causing the slowdown. (hover your mouse over each join to see the details) You'll want to make sure that you are getting an index seek and not a table scan.

    I would assume what is happening is that SQL is being forced to pull everything from one table into memory in order to do one of the joins. Sometimes reversing the order that you join the tables will also help things.

  • A general rule of thumb is that OUTER JOINs cause the number of rows in a result set to increase, while INNER JOINs cause the number of rows in a result set to decrease. Of course, there are plenty of scenarios where the opposite is true as well, but it's more likely to work this way than not. What you want to do is keep the size of the result set as small as possible for as long as possible.

    Since both joins match on the first table, changing up the order won't effect the accuracy of the results. Therefore, you probably want to do the INNER JOIN before the LEFT JOIN:

    SELECT * 
    FROM TblA
    INNER JOIN DifferentDbCatalog.dbo.TblC on TblA.ID = TblC.TblAID
    LEFT JOIN freetexttable ( TblB, *, 'query' ) on TblA.ID = [Key]

    This probably isn't good enough to fully explain the behavior you're seeing, so you'll still want to examine the execution plan used for each query, and probably add an index as suggested earlier. This is still a good principle to learn, though.

  • Putting freetexttable(TblB, *, 'query') into a temp table may help if it's getting called repeatedly in the execution plan.

    From eed3si9n


Post a Comment