28

I have a query to find certain customers from a table.

SELECT COUNT(*)
  FROM CUSTOMER
 WHERE amount <> 0
   AND customerid = 22

There is an index on customerid, so the DB scans all rows with customerid = 22.

Since the result is processed by checking whether the count returns zero or more than zero, how can I optimize the query? I.e. such that at the first customer row with amount <> 0 the query returns 0 else if all rows are = 0, then return 1.

Carlo V. Dango
  • 13,322
  • 16
  • 71
  • 114

4 Answers4

34
select case
         when exists (select *
                      from   customer
                      where  amount <> 0
                             and customerid = 22) then 1
         else 0
       end  as non_zero_exists
Martin Smith
  • 438,706
  • 87
  • 741
  • 845
  • 4
    Would it be more efficient to replace 'select *' with 'select customerid' or maybe 'select 1' ? – Carlo V. Dango Feb 17 '11 at 22:17
  • 1
    @CarloV.Dango from memory SQL Server 2005 and up has added optimizations that makes exists and count checks like above the same speed. – Bertus Kruger Mar 04 '14 at 01:03
  • @BertusKruger That only applies if the `COUNT` test against `0` is in the query, which it is not in the original question. I wonder if `TOP 1` would optimize it. – NetMage Mar 26 '19 at 17:19
8

First index on customerid and amount

CREATE INDEX customer_idx ON customer(customerid, amount); 

then rewrite your query as

IF EXISTS (SELECT customerid
    FROM customer
    WHERE amount > 0 -- I am assuming here that amount cannot be a negative number.
    AND customerid = 22)
   SELECT 1
ELSE
   SELECT 0

This should result in an index seek on customer_idx. Otherwise you'll need to scan all rows for that customer (which your question seems to imply could be a lot).

Chris Shain
  • 50,833
  • 6
  • 93
  • 125
4

Seems straight forward enough

IF EXISTS ( SELECT customerid
            FROM   customer
            WHERE  amount <> 0
                  and customerid = 22))
   SELECT 1
ELSE
   SELECT 0
Conrad Frix
  • 51,984
  • 12
  • 96
  • 155
2

An alternative to EXISTS

select ISNULL((select TOP 1 1
               from customer
               where amount <> 0
                 and customerid = 22),0)

I already assumed that you will have an index on (customerid) or better (customerid,amount).

RichardTheKiwi
  • 105,798
  • 26
  • 196
  • 262