thomasb
thomasb

Reputation: 6045

SQL LIKE with parameter : huge performance hit

I have this query :

select top 100 id, email, amount from view_orders
    where email LIKE '%test%' order by created_at desc

It takes less than a second to run.

Now I want to parameterize it :

declare @m nvarchar(200)
set @m = '%test%'
SELECT TOP 100 id, email, amount FROM view_orders
    WHERE email LIKE @m ORDER BY created_at DESC

After 5 minutes, it's still running. With any other kind of test on parameters (if I replace the "like" with "="), it falls down to the first query level of performance.

I am using SQL Server 2008 R2.

I have tried with OPTION(RECOMPILE) , it drops to 6 seconds, but it's still much slower (the non-parameterized query is instantaneous). As it's a query that I expect will be run often, it's an issue.

The table's column is indexed, but the view is not, I don't know if it can make a difference.

The view joins 5 tables : one with 3,154,333 rows (users), one with 1,536,111 rows (orders), and 3 with a few dozen rows at most (order type, etc). The search is done on the "user" table (with 3M rows).

Hard-coded values :
Execution plan using hard-coded values

Parameters :
Execution plan using parameters

Update

I have run the queries using SET STATISTICS IO ON. Here are the result (sorry I don't know how to read that) :

Hard-coded values:

Table 'currency'. Scan count 1, logical reads 201.

Table 'order_status'. Scan count 0, logical reads 200.

Table 'payment'. Scan count 1, logical reads 100.

Table 'gift'. Scan count 202, logical reads 404.

Table 'order'. Scan count 95, logical reads 683.

Table 'user'. Scan count 1, logical reads 7956.

Parameters :

Table 'currency'. scan count 1, logical reads 201.

Table 'order_status'. scan count 1, logical reads 201.

Table 'payment'. scan count 1, logical reads 100.

Table 'gift'. scan count 202, logical reads 404.

Table 'user'. scan count 0, logical reads 4353067.

Table 'order'. scan count 1, logical reads 4357031.

Update 2

I have since seen a "force index usage" hint :

SELECT TOP 100 id, email, amount
FROM view_orders with (nolock, index=ix_email)
WHERE email LIKE @m
ORDER BY created_at DESC

Not sure it would work though, I don't work at this place anymore.

Upvotes: 4

Views: 2057

Answers (5)

greyalien007
greyalien007

Reputation: 510

The estimated execution plan for the parameterized version is clearly not right. I don't believe I've seen a query with 100% estimated cost twice! As the cost is supposed to total 100%. It's also interesting that it believes it needs to start with orders when you're clearly filtering by something on the user table.

I'd rebuild your statistics on all of the tables that are referenced in the view.

update statistics <tablename> with resample

Do one of these for each table involved.

You can attempt running the sql directly (copy paste view body into sql) both parameterized and not to see if it's the view sql is having issues with.

At the end of the day even when you get this fixed it's really only a stop gap. You have 3million users and every time you run the query sql has to go through all 3million records (the 75% scan in your top query) to find all the possible records. The more users you get the slower the query gets. Non-fulltext indexes can't be used for a like query with wildcards at the front.

In this case you can think about a sql index like a book index. Can you use a book index with "part" of a word to find anything quickly? Nope, you've got to scan the whole index to figure out all the possibilities.

You should really consider a full text index on your view.

Upvotes: 0

MLT
MLT

Reputation: 514

It could be a parameter sniffing problem. Better indexes or a full text search are the way to go but you might be able to get a workable compromise. Try:

SELECT TOP 100 A, B, C FROM myview WHERE A LIKE '%' + @a + '%'
OPTION (OPTIMIZE FOR (@a = 'testvalue'));

(like Sean Coetzee suggests, I wouldn't pass in the wildcard in the parameter)

Upvotes: 3

Sean
Sean

Reputation: 1474

What happens if you try:

set @a = 'test'
select top 100 A, B, C 
  from myview 
 where A like '%' + @a + '%'

I've tried a test on some dummy data and it looks like it may be faster.

Upvotes: 0

vhadalgi
vhadalgi

Reputation: 7189

CREATE INDEX index_name ON myview (A);
CREATE INDEX index_name ON myview (B);
CREATE INDEX index_name ON myview (C);

declare @a nvarchar(200)
set @a = '%testvalue%'
SELECT TOP 100 A, B, C FROM myview WHERE A LIKE @a

Upvotes: 0

Yaugen Vlasau
Yaugen Vlasau

Reputation: 2228

You will definetly win when you add an index to the A column. Some time the index suggestion can be borrowed by SQL Server management studio. Paste you query and press Display Estimated Execution Plan button

Upvotes: 0

Related Questions