7

Say my query looks like:

SELECT t1, t2
FROM t1
  LEFT JOIN t2 ON (t1.id = t2.id AND t2.userid = @userid)
WHERE t1.enabled = 1 AND
      t1.startDate <= ??? AND 
      (t1.counter = -1 OR
       t2.counter IS NULL OR
       (t1.counter > t2.counter)

Now this table might have a few hundred thousand rows in it.

Would you suggest I put an index on the JOIN clause only like this?

  t2.id t2.userid

What about the where clause? Or is the join clause more important?

I realize testing is important, but in theory what should be done?

(This is for SQL Server 2000)

1
  • I would say both but note that updates and inserts will be slower the more indexes you add.
    – Steve Wellens
    Jul 11, 2012 at 15:57

2 Answers 2

5

I would recommend to always put a non-clustered index on the columns that will be used in JOIN conditions - the foreign key columns. This helps in several ways - JOIN operations will be faster, and enforcing the FK constraint (checking whether there's a child row attached when attempting to delete the parent row) will also benefit from those indices.

Then check to see how your system performs. If it performs below your expectations - carefully add one index and see if the overall system performance improves. If not: remove the index again. Repeat over until you're happy with the performance. Columns used in WHERE or ORDER BY clauses are the prime candidates for those indices - but don't over-index! That's even worse than having no indices at all.

See Kimberly The Queen of Indexing Tripp's excellent blog post - Indexes: just because can, doesn't mean you should! on that very topic.

3
  • 2
    Her blog posts about indexing is a exceptional reading... Jul 12, 2012 at 17:53
  • I'm not sure if trial and error is a good approach? Jun 1, 2016 at 4:04
  • 2
    @PaulWasilewski: if you have a better, more efficient way - please do share it with us!
    – marc_s
    Jun 1, 2016 at 12:08
0

Plus to what was given above. I'll give you my index suggestion for your specific query:

--Added to show you how you use the SELECT columns in the IX INCLUDE section.

SELECT t1.col1, t1.col2  
  , t2.colA, t2.colB
FROM t1
  LEFT JOIN t2 ON (t1.id = t2.id AND t2.userid = @userid)
WHERE t1.enabled = 1 AND
      t1.startDate <= '2021-02-26 19:03:04.437' AND 
      (t1.counter = -1 OR
       t2.counter IS NULL OR
       t1.counter > t2.counter)

--Index1:

create index ix_t1 on t1 (enabled, startDate, counter) include (col1, col2, id)

--notice i added column "id" because if it's your PK it helps to add it to the INCLUDES

--Index2:

create index ix_t2 on t2 (counter) include (colA, colB, userid)

-- assuming useid is your PK.

that's my attempt at indexing it. I maybe off just a little bit so please test it and adjust as needed.

Also I would highly recommend rewriting that query and substitute the OR with UNION. These queries with OR's have a tendency to go row-by-row and are very slow on large tables. The UNION version should look something like this. (again please test it I may be off just a bit):

--1st OR

  SELECT t1.col1, t1.col2
  , t2.colA, t2.colB
FROM t1
  LEFT JOIN t2 ON (t1.id = t2.id AND t2.userid = @userid)
WHERE t1.enabled = 1 AND
  t1.startDate <= ??? AND 
  t1.counter = -1 
UNION--2ND OR
  SELECT t1.col1, t1.col2
      , t2.colA, t2.colB
    FROM t1
      LEFT JOIN t2 ON (t1.id = t2.id AND t2.userid = @userid)
    WHERE t1.enabled = 1 AND
      t1.startDate <= ??? AND 
      t2.counter IS NULL OR
UNION  --3rd OR
  SELECT t1.col1, t1.col2
      , t2.colA, t2.colB
    FROM t1
      LEFT JOIN t2 ON (t1.id = t2.id AND t2.userid = @userid)
    WHERE t1.enabled = 1 AND
      t1.startDate <= ??? AND 
       t1.counter > t2.counter

good luck.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.