I’m using the following LINQ to SQL query on a SQL Server Compact DB …
from article in context.OutboundArticles
where !article.IsDeleted
select article
… which generates the following SQL:
SELECT [t0].[Id], [t0].[Text], [t0].[IsDeleted]
FROM [OutboundArticle] AS [t0]
WHERE NOT ([t0].[IsDeleted] = 1)
This would be perfectly fine if it weren’t for the fact that there’s an index on the IsDeleted column and SQL Server Compact will not use the index unless the SQL looks like this:
SELECT [t0].[Id], [t0].[Text], [t0].[IsDeleted]
FROM [OutboundArticle] AS [t0]
WHERE [t0].[IsDeleted] = CONVERT(BIT, 0)
So the question is: How do I convince LINQ to SQL to generate the “CONVERT(BIT, 0)”? I’ve already tried the following …
from article in context.OutboundArticles
where article.IsDeleted == Convert.ToBoolean(0)
select article
… but the generated SQL looks the same.
After a lot of digging it seems LINQ to SQL cannot be convinced to generate the
CONVERT(BIT, 0)into the query. However, it can be forced to use a parameter instead of a literal in the WHERE clause, namely by compiling the query first, as follows:When we run this query, the following SQL is generated:
Note the comment, @p0 seems to be typed appropriately for SQL Server Compact to actually use the index. I’ve verified this with the program below. The program first fills a new DB with 1000000 rows and then queries it with either the compiled or the ordinary query. On my machine, the timings are obvious (average from 3 runs, first discarded):
In both cases the query is only executed exactly once, so the compiled query does not have any advantage from the actual compilation. Further evidence that the compiled query actually uses the index while the ordinary does not comes when we manually delete the index in the DB and then run the same queries again (average from 3 runs, first discarded):