1

I use raw SQL with parameters in Dapper. Query speed is normal.

Something like this:

string sql = "SELECT * FROM SomeTable WHERE messages IN ('Volvo', 'BMW', 'Ford', 'Mazda')"
var results = conn.Query(sql);

When I change parameters with @messages, the speed is too slow:

string sql = "SELECT * FROM SomeTable WHERE messages IN (@cars)"
string[] cars = { "Volvo", "BMW", "Ford", "Mazda" };
var results = conn.Query(sql, new {cars});

PS: string[] size is almost 300.

12
  • 1
    The query is executed by the server, not Dapper. Its performance depends on whether messages is indexed or not. Commented May 26, 2021 at 12:55
  • 1
    maybe you can trace the executed query and check for the plan to determine what is different ? Commented May 26, 2021 at 12:57
  • 1
    string[] size is almost 300. did you try with a raw string with 300 items? It's not possible to pass an array of values as a parameter, so Dapper will actually generate an IN clause with the values. The two queries should be identical. Commented May 26, 2021 at 12:59
  • 2
    @PanagiotisKanavos Actually I believe Dapper will create a query with 300 sql parameters vs the other query that has the values hard coded in the query. So there might be some overhead from using parameters but I doubt it would be noticeable. Commented May 26, 2021 at 13:04
  • 1
    @juharr in that case, the server won't be able to calculate statistics for the values. If sometable is too small, the server may decide to use a scan instead of a seek, especially since it needs to retrieve all columns. BTW without the table schema and row counts, we're as blind as the server. Commented May 26, 2021 at 13:06

2 Answers 2

4

If you pass string as parameter, Dapper treats it as nvarchar type. So if your messages is varchar type and the SomeTable is huge, even if it's indexed, the speed could be really slow. DbString may solve this problem.

cars.ToList().Select(x => new DbString { Value = x, IsFixedLength = false, IsAnsi = true });
Sign up to request clarification or add additional context in comments.

2 Comments

For list-type values, Dapper rewrites the query
hi, any pseudo code about how to solve the problem raised by the author? @HansKesting
1

(would be a mess as a comment) (I think there might be some syntax error in second one and there shouldn't be parentheses.)

The two queries would generate different SQL sent to backend. ie: with MS SQL server they would look like:

First one:

SELECT * FROM SomeTable WHERE messages IN ('Volvo', 'BMW', 'Ford', 'Mazda')

Second one:

exec sp_executesql N'SELECT * FROM SomeTable WHERE messages IN (@cars1, @cars2, @cars3, @cars4)',
N'@cars1 nvarchar(4000),@cars2 nvarchar(4000),@cars3 nvarchar(4000),@cars4 nvarchar(4000)',
@cars1=N'Volvo',@cars2=N'BMW',@cars3=N'Ford',@cars4=N'Mazda'

IMHO there are better ways of doing IN queries depending on your backend.

2 Comments

The real difference is that in the first query, the query optimizer can calculate statistics from the values, as they're part of the query itself. In the second, the values are unknown, only their number is known. This is little better than eg a TVP where even the count is unknown
@PanagiotisKanavos, yes and it is a difference. I wouldn't do a parametric in query like this (it could be translated to EXISTS, INNER JOIN ...). Actually in one real world scenario for MS SQL server, I ended creating a CLR function. With over 20K parameters it returned the result under a second against apprx. 500K rows.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.