views:

51

answers:

4

I have a table which has a bunch of columns but the two relevant ones are:

Due_Amount MONEY
Bounced_Due_Amount MONEY

I have a SQL query like the following

SELECT * FROM table WHERE (Due_Amount > 0 OR Bounced_Due_Amount > 0)

Would the best index to put on this table for SQL Server 2008 be an index which includes both columns in the index, or should I put an separate index on each column?

A: 

Specifically for this query, it would be best to create an index on both columns in the order they are used in the where clause. Otherwise the index might not be used.

Koen
+5  A: 

An Index can't be used on an OR like that. try this:

SELECT * FROM table WHERE Due_Amount > 0
UNION ALL  
SELECT * FROM table Bounced_Due_Amount > 0
--use "UNION" if Due_Amount and Bounced_Due_Amount could both >0 at any one time

have an index on Due_Amount and another on Bounced_Due_Amount.

It might be better to redesign your table. Without knowing your business logic or table, I'm going to guess that you could have a "Bounced" Y/N or 1/0 char/bit column and just a "Due_Amount" column. Add an index on that "Due_Amount" and the query would just be:

SELECT * FROM table WHERE Due_Amount > 0

you could still differentiate between a Bounced or not row. This will not work if you need to have both a bounced and non-bounced due amount at the same time.

KM
To match the output, you would need to use UNION, not UNION ALL, and then you'll have a DISTINCT operation
G Mastros
+1 This is exactly the type of thing UNION ALL is for
Chris Lively
+1 - it's worth a note that duplicates could be returned using UNION ALL i.e. if a record has both Due_Amount > 0 and Bounce_Due_Amount > 0, this would return that record twice. If you switched to UNION, those dupes would not be returned, but at a performance cost (as it would have to do a distinct). UNION ALL is best for performance, if you can cope with that difference
AdaTheDev
If Due_Amount is greater than zero, and Bounced_Due_Amount is also greater than zero, the UNION ALL query would return 2 rows instead of 1.
G Mastros
@G Mastros and @AdaTheDev, I added a note about "UNION ALL" vs "UNION" in my answer. I was thinking that either Due_Amount or Bounced_Due_Amount would be populated (hence no dups) but I guess that they could both be in use.
KM
Although very unlikely it is possible they will both be > 0. I will give a try to the UNION and see if that helps verses the OR statement. Unfortunately I can't redesign because I need to know the amount that was bounced which is separate from the original due amount on the line (accounting systems suck especially when you deal with accountants).
Chuck Haines
@Chuck Haines said `accounting systems suck especially when you deal with accountants`, and I say to that `how true!!!`
KM
A: 

My guess is that you would be better off with an index on each individual column. Having it on both won't help any more than having it on just the first column unless you have other queries that would use the compound index.

Your best bet is to try the query with an index on one column, an index on the other column, and two indexes - one on each column. Do some tests with each (on real data, not test data) and see which works best. Take a look at the query plans to understand why.

Depending on the specific data (both size and cardinality) SQL Server may end up using one, both, or possibly even neither index. The only way to know for sure is to test them each.

Tom H.
A: 

Technically, you can have an index on a persisted computed column and use the computed column instead of the OR condition in the query, see Creating Indexes on Computed Columns:

alter table [table] add Max_Due_Amount as
   case 
    when Due_Amount > Bounced_Due_Amount the Due_Ammount
    else Bounced_Due_Amount
   end
   persisted;
go

create index idxTableMaxDueAmount on table (Max_Due_Amount );
go

SELECT * FROM table WHERE Max_Due_Amount > 0;

But in general I'd recommend using the UNION approach like KM suggested.

Remus Rusanu