LINQ + .Contains(s) + sp_executesql = big performance problemI've discovered that LINQ auto-generated SQL search commands performs 3-4 times slower than manually created. And performance is much worse with bigger tables (2M+ records).<br><br>I moved fast query on top. Cleaned plan cache, updated statistics but LINQ generated query still performs 4*N times slower. I’ve tested this on 5 different SQL servers (i386, x64, v9.0.3282 SP2 CU9) and results always the same.<br><br>It looks like problem lies in SQL server and not in LINQ. But if it affects all Microsoft databases worldwide then its a bummer. At this moment I don't know any workaround for this problem. If you have any info or workaround for this issue then please post it here.<br><br>Note: Table/Index must have at least 2 000 000 records to see huge difference, my guess, it must not fit (be cached) into the RAM). I guess LINQ users with big databases are screwed - no FullText support and ‘LIKE’ is slow as *** <img height=19 alt=Smile src="http://forums.microsoft.com/MSDN/emoticons/emotion-1.gif" width=19>.<br><br> <hr> Test Code: <hr> <code><br>-- Make sure we have up-to-date statistics<br>UPDATE STATISTICS dbo.TestTable1 WITH FULLSCAN<br><br>-- Remove all cached query plans and<br>-- execution contexts from the plan cache.<br>DBCC FREEPROCCACHE <br><br><span style="color:rgb(0,128,0)">-- Custom query, no parameters: Takes 6 seconds. Use Index/Table Scan.</span><br><span style="color:rgb(0,0,255)">exec </span><span style="color:rgb(128,0,0)">sp_executesql</span> N<span style="color:rgb(255,0,0)">'SELECT Count(*) FROM dbo.TestTable1 WHERE [Name] LIKE ''%pattern%'''</span><br><br>-- Make sure we have up-to-date statistics<br>UPDATE STATISTICS dbo.TestTable1 WITH FULLSCAN<br>-- Remove all cached query plans and<br>-- execution contexts from the plan cache.<br>DBCC FREEPROCCACHE<br><br><span style="color:rgb(0,128,0)">-- Query generated by LINQ (row.Name.Contains(&quot;pattern&quot;)) Takes 20 seconds. Use Index Seek.</span><br><span style="color:rgb(0,0,255)">exec </span><span style="color:rgb(128,0,0)">sp_executesql</span> N<span style="color:rgb(255,0,0)">'SELECT Count(*) FROM dbo.TestTable1 WHERE [Name] LIKE @p0'</span>, N<span style="color:rgb(255,0,0)">'@p0 nvarchar(9)'</span>, @p0=<span style="color:rgb(255,0,0)">'%pattern%'</span><br><br></code> <hr> Code to create and fill TestTable1 table:<br> <hr> <code><br>-- Drop test table.<br>DROP TABLE [TestTable1]<br>-- Columns<br>CREATE TABLE [dbo].[TestTable1]<br>(<br>      [Name] [nvarchar] (100) COLLATE Latin1_General_CI_AS NOT NULL<br>) ON [PRIMARY]<br>-- Constraints and indexes<br>CREATE NONCLUSTERED INDEX [IX_TestTable1] ON [dbo].[TestTable1] ([Name]) ON [PRIMARY]<br><br>-- Insert 100 records into temp table.<br>DECLARE @Table AS TABLE (Id nvarchar(36) PRIMARY KEY)<br>INSERT INTO @Table SELECT newid() UNION SELECT newid() UNION SELECT newid() UNION SELECT newid()<br>INSERT INTO @Table SELECT TOP 96 newid() FROM @Table AS t0<br>CROSS JOIN @Table AS t1 CROSS JOIN @Table AS t2 CROSS JOIN @Table AS t3<br>-- Generate  2 000 000 records (8 min).<br>INSERT INTO dbo.TestTable1 SELECT t0.Id+t1.Id FROM @Table AS t0<br>CROSS JOIN @Table AS t1 CROSS JOIN @Table AS t2<br>INSERT INTO dbo.TestTable1 SELECT t0.Id+t1.Id FROM @Table AS t0<br>CROSS JOIN @Table AS t1 CROSS JOIN @Table AS t2<br>SELECT Count(*) FROM dbo.TestTable1<br><br></code> <hr> <br>Evaldas Jocys<br>http://www.jocys.com/<br>© 2009 Microsoft Corporation. All rights reserved.Wed, 10 Dec 2008 23:35:02 Z55ae6f5c-ddf2-4713-b3e2-f63278f60d7fhttp://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/55ae6f5c-ddf2-4713-b3e2-f63278f60d7f#55ae6f5c-ddf2-4713-b3e2-f63278f60d7fhttp://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/55ae6f5c-ddf2-4713-b3e2-f63278f60d7f#55ae6f5c-ddf2-4713-b3e2-f63278f60d7fEvaldas Jocyshttp://social.msdn.microsoft.com/Profile/en-US/?user=Evaldas%20JocysLINQ + .Contains(s) + sp_executesql = big performance problemI've discovered that LINQ auto-generated SQL search commands performs 3-4 times slower than manually created. And performance is much worse with bigger tables (2M+ records).<br><br>I moved fast query on top. Cleaned plan cache, updated statistics but LINQ generated query still performs 4*N times slower. I’ve tested this on 5 different SQL servers (i386, x64, v9.0.3282 SP2 CU9) and results always the same.<br><br>It looks like problem lies in SQL server and not in LINQ. But if it affects all Microsoft databases worldwide then its a bummer. At this moment I don't know any workaround for this problem. If you have any info or workaround for this issue then please post it here.<br><br>Note: Table/Index must have at least 2 000 000 records to see huge difference, my guess, it must not fit (be cached) into the RAM). I guess LINQ users with big databases are screwed - no FullText support and ‘LIKE’ is slow as *** <img height=19 alt=Smile src="http://forums.microsoft.com/MSDN/emoticons/emotion-1.gif" width=19>.<br><br> <hr> Test Code: <hr> <code><br>-- Make sure we have up-to-date statistics<br>UPDATE STATISTICS dbo.TestTable1 WITH FULLSCAN<br><br>-- Remove all cached query plans and<br>-- execution contexts from the plan cache.<br>DBCC FREEPROCCACHE <br><br><span style="color:rgb(0,128,0)">-- Custom query, no parameters: Takes 6 seconds. Use Index/Table Scan.</span><br><span style="color:rgb(0,0,255)">exec </span><span style="color:rgb(128,0,0)">sp_executesql</span> N<span style="color:rgb(255,0,0)">'SELECT Count(*) FROM dbo.TestTable1 WHERE [Name] LIKE ''%pattern%'''</span><br><br>-- Make sure we have up-to-date statistics<br>UPDATE STATISTICS dbo.TestTable1 WITH FULLSCAN<br>-- Remove all cached query plans and<br>-- execution contexts from the plan cache.<br>DBCC FREEPROCCACHE<br><br><span style="color:rgb(0,128,0)">-- Query generated by LINQ (row.Name.Contains(&quot;pattern&quot;)) Takes 20 seconds. Use Index Seek.</span><br><span style="color:rgb(0,0,255)">exec </span><span style="color:rgb(128,0,0)">sp_executesql</span> N<span style="color:rgb(255,0,0)">'SELECT Count(*) FROM dbo.TestTable1 WHERE [Name] LIKE @p0'</span>, N<span style="color:rgb(255,0,0)">'@p0 nvarchar(9)'</span>, @p0=<span style="color:rgb(255,0,0)">'%pattern%'</span><br><br></code> <hr> Code to create and fill TestTable1 table:<br> <hr> <code><br>-- Drop test table.<br>DROP TABLE [TestTable1]<br>-- Columns<br>CREATE TABLE [dbo].[TestTable1]<br>(<br>      [Name] [nvarchar] (100) COLLATE Latin1_General_CI_AS NOT NULL<br>) ON [PRIMARY]<br>-- Constraints and indexes<br>CREATE NONCLUSTERED INDEX [IX_TestTable1] ON [dbo].[TestTable1] ([Name]) ON [PRIMARY]<br><br>-- Insert 100 records into temp table.<br>DECLARE @Table AS TABLE (Id nvarchar(36) PRIMARY KEY)<br>INSERT INTO @Table SELECT newid() UNION SELECT newid() UNION SELECT newid() UNION SELECT newid()<br>INSERT INTO @Table SELECT TOP 96 newid() FROM @Table AS t0<br>CROSS JOIN @Table AS t1 CROSS JOIN @Table AS t2 CROSS JOIN @Table AS t3<br>-- Generate  2 000 000 records (8 min).<br>INSERT INTO dbo.TestTable1 SELECT t0.Id+t1.Id FROM @Table AS t0<br>CROSS JOIN @Table AS t1 CROSS JOIN @Table AS t2<br>INSERT INTO dbo.TestTable1 SELECT t0.Id+t1.Id FROM @Table AS t0<br>CROSS JOIN @Table AS t1 CROSS JOIN @Table AS t2<br>SELECT Count(*) FROM dbo.TestTable1<br><br></code> <hr> <br>Evaldas Jocys<br>http://www.jocys.com/<br>Fri, 07 Nov 2008 15:02:31 Z2008-12-01T22:59:31Zhttp://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/55ae6f5c-ddf2-4713-b3e2-f63278f60d7f#e9e64709-e4c5-4c8f-8d3f-ad277f3cab71http://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/55ae6f5c-ddf2-4713-b3e2-f63278f60d7f#e9e64709-e4c5-4c8f-8d3f-ad277f3cab71KristoferA - Huagati Systemshttp://social.msdn.microsoft.com/Profile/en-US/?user=KristoferA%20-%20Huagati%20SystemsLINQ + .Contains(s) + sp_executesql = big performance problem<p>The execution plan for the parameterized (stored proc) version is generated without the optimizer knowing what you're going to pass in as @p0. The same will happen if you create a stored procedure with the same query. Because of this, the optimizer decides to opt for an index-seek based execution plan - this will make most sense unless there is a leading wildcard in the lookup criteria (@p0) so the SQL optimizer makes the assumption that most of the time it will be used for &quot;small&quot; lookups.</p> <p align=left> </p> <p align=left>The seek-instead-of-scan could be avoided with a SQL optimizer hint but unfortunately there is no built-in way to pass optimizer hints to the db in Linq queries today. (Although that can be worked around with an extension method to IQueryable if you want to go down that route.)</p> <p align=left> </p> <p align=left>---</p> <p align=left> </p> <p align=left>A couple of general observations with regards to query performance on your sample table:</p> <p align=left> </p> <p align=left>1) Do you really need to use <em>like '%pattern%'</em>  (.Contains) on a large table/large set of data? Or would <em>like 'pattern%'</em> (.StartsWith) do?</p> <p align=left> </p> <p align=left>If you need to match something inside a string, you should reconsider your table design and maybe have a separate lookup table (or separate columns in your table) where you break up the &quot;name&quot; column so you can do <em>like 'pattern%'</em> matches. Matching with both leading and trailing wild cards means that the entire index need to be scanned (40k reads in your first query), and every index entry need to be scanned to find if the pattern exists anywhere in the column whereas for example <em>like 'pattern%'</em> would only scan or seek only the relevant portion of the index.</p> <p align=left> </p> <p align=left>The non-sp-parameterized version of the query against the 2M row test table still does 40k reads due to the full index scan. The parameterized one does 55k reads due to the seek so it adds a little bit of I/O overhead but <u>both</u> are still way too expensive I/O wise if this is just a simple name lookup. In contrast, removing the leading wild card brings both queries down to 5/525 reads (5 when there is no match, 525 when there is a match).</p> <p align=left> </p> <p align=left>If the &quot;Name&quot; column in your table will store a person name, consider breaking it up into separate indexed columns first, last, middle names etc.</p> <p align=left> </p> <p align=left>2) Since your test table does not have a primary key or any other column than the &quot;Name&quot; column, why not cluster it on the &quot;Name&quot; column? If always doing lookups against this column only you may as well have the data stored in order. Also consider adding a primary key + a clustered index (either on the PK or the &quot;Name&quot; column) to avoid the internal auto-generated heap pk / &quot;funny&quot; storage order.</p> <p align=left> </p> <p align=left>3) Does the spread/content of values in the generated sample data represent the distribution of values in the real world table you're working with? This particular example won't be affected but other queries can be negatively affected by a low spread of values, so when doing this kind of tests make sure the sample/test data you're using resembles the real world data you will be working with as closely as possible.</p>Mon, 10 Nov 2008 03:10:25 Z2008-11-10T03:10:25Zhttp://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/55ae6f5c-ddf2-4713-b3e2-f63278f60d7f#1dc5188c-8de3-4f0c-99a2-089412abc8c7http://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/55ae6f5c-ddf2-4713-b3e2-f63278f60d7f#1dc5188c-8de3-4f0c-99a2-089412abc8c7KristoferA - Huagati Systemshttp://social.msdn.microsoft.com/Profile/en-US/?user=KristoferA%20-%20Huagati%20SystemsLINQ + .Contains(s) + sp_executesql = big performance problem<p>I/O stats:</p> <p align=left> </p><font color="#0000ff" size=2><font color="#0000ff" size=2> <p>exec</font></font><font size=2> </font><font color="#800000" size=2><font color="#800000" size=2>sp_executesql</font></font><font size=2> N</font><font color="#ff0000" size=2><font color="#ff0000" size=2>'SELECT Count(*) FROM dbo.TestTable1 WHERE [Name] LIKE ''%pattern%'''</p></font></font> <p align=left><font face=Arial size=2></font> </p><font size=1> <p><font face=Courier color="#000000" size=2>Table 'TestTable1'. Scan count 1, <u>logical reads 39216</u>, physical reads 0, read-ahead reads 39061, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.</font></p> <p> </p> <p align=left>---</p> <p align=left> </p><font color="#0000ff" size=2><font color="#0000ff" size=2> <p>exec</font></font><font size=2> </font><font color="#800000" size=2><font color="#800000" size=2>sp_executesql</font></font><font size=2> N</font><font color="#ff0000" size=2><font color="#ff0000" size=2>'SELECT Count(*) FROM dbo.TestTable1 WHERE [Name] LIKE @p0'</font></font><font color="#808080" size=2><font color="#808080" size=2>,</font></font><font size=2> N</font><font color="#ff0000" size=2><font color="#ff0000" size=2>'@p0 nvarchar(9)'</font></font><font color="#808080" size=2><font color="#808080" size=2>,</font></font><font size=2> @p0</font><font color="#808080" size=2><font color="#808080" size=2>=</font></font><font color="#ff0000" size=2><font color="#ff0000" size=2>'%pattern%'</p> <p> </p><font size=1> <p><font face=Courier color="#000000" size=2>Table 'TestTable1'. Scan count 1, <u>logical reads 54912</u>, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.</font></p> <p> </p> <p align=left><font color="#000000">---</font></p> <p align=left> </p><font color="#0000ff" size=2><font color="#0000ff" size=2> <p>exec</font></font><font color="#000000" size=2> </font><font color="#800000" size=2><font color="#800000" size=2>sp_executesql</font></font><font color="#000000" size=2> N</font><font color="#ff0000" size=2><font color="#ff0000" size=2>'SELECT Count(*) FROM dbo.TestTable1 WHERE [Name] LIKE @p0'</font></font><font color="#808080" size=2><font color="#808080" size=2>,</font></font><font color="#000000" size=2> N</font><font color="#ff0000" size=2><font color="#ff0000" size=2>'@p0 nvarchar(9)'</font></font><font color="#808080" size=2><font color="#808080" size=2>,</font></font><font color="#000000" size=2> @p0</font><font color="#808080" size=2><font color="#808080" size=2>=</font></font><font color="#ff0000" size=2><font color="#ff0000" size=2>'pattern%'</p> <p> </p><font face=Courier color="#000000" size=2> <p>Table 'TestTable1'. Scan count 1, <u>logical reads 5</u>, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.</p></font></font></font></font></font></font></font>Mon, 10 Nov 2008 03:15:29 Z2008-11-10T03:15:29Zhttp://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/55ae6f5c-ddf2-4713-b3e2-f63278f60d7f#32b92e8f-ef39-4978-9dc8-57c7829ed0dbhttp://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/55ae6f5c-ddf2-4713-b3e2-f63278f60d7f#32b92e8f-ef39-4978-9dc8-57c7829ed0dbEvaldas Jocyshttp://social.msdn.microsoft.com/Profile/en-US/?user=Evaldas%20JocysLINQ + .Contains(s) + sp_executesql = big performance problem<font size=2><span style="font-family:Arial">At this moment I have two incomplete solutions because both require </span></font><font size=2><span style="font-family:Arial">extension of current LINQ to SQL classes</span></font><font size=2><span style="font-family:Arial">:<br><br><span style="font-weight:bold">A)</span> Pass option WITH (INDEX = 0) to LINQ query (seems like there is no way to do that):<br></span></font><font size=2><span style="font-family:Arial"><span style="color:rgb(128,128,128)">(Submited by  Erland Sommarskog, SQL Server MVP, esquel@sommarskog.se)</span><br></span></font><font size=2><span style="font-family:Arial">This will force SQL server to use index scan so search will be multiple times faster.<br></span></font><br><font size=2><span style="font-family:Arial">exec sp_executesql N'SELECT Count(*) FROM dbo.TestTable1 <span style="color:rgb(0,128,0)">WITH (INDEX = 0)</span> WHERE [Name] LIKE @p0', N'@p0 nvarchar(9)', @p0='%pattern%'<br><br><span style="font-weight:bold">B)</span> Use SQL Full-Text extension to LINQ to SQL classes</span></font><font size=2><span style="font-family:Arial"> which doesn't exist. If extension exist then I can't find it on Google. </span></font><font size=2><span style="font-family:Arial">SQL </span></font>Full-Text <font size=2><span style="font-family:Arial"><span style="font-style:italic">CONTAINS(s)</span> would be enough.</span></font><br><font size=2><span style="font-family:Arial"><br>All I can do now is to extend command execution time by using <span style="font-style:italic">db.CommandTimeout = 120</span> when using search. It doesn't solve the performance problem but at least it it won't throw timeout error when using search.<br><br><br><br>P.S.: I've also found some interesting examples of </span></font><span class=TableName><span id="lblForumName_Header">LLBLGen:</span></span><br>http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=13677<br><br><code>''' Class which defines the custom mapping between ServiceCenterFunctions.FullTextSearch and CONTAINS<br>Public Class MyCustomFunctionMappings Inherits FunctionMappingStore<br>    Public Sub New()<br>        <span style="color:rgb(0,0,255)">Me.Add(New FunctionMapping(GetType(MyCustomFunctions), &quot;FullTextSearch&quot;, 2, &quot;CONTAINS({0}, {1})&quot;))</span><br>    End Sub<br>End Class<br>...<br><span style="color:rgb(0,0,255)">Dim q1 = From p In GetProjects() Where MyCustomFunctions.FullTextSearch(p.Description, searchTerm) Select p.Id</span></code><br><br>But this involves third party library. Simpler Microsoft's LINQ to SQL extension would be much better solution.<br><br><br>Evaldas Jocys<br>http://www.jocys.com/<br>Mon, 10 Nov 2008 11:26:52 Z2008-11-10T11:26:52Zhttp://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/55ae6f5c-ddf2-4713-b3e2-f63278f60d7f#cf21d194-c6a5-4278-b36f-a6cd13334d1fhttp://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/55ae6f5c-ddf2-4713-b3e2-f63278f60d7f#cf21d194-c6a5-4278-b36f-a6cd13334d1fKristoferA - Huagati Systemshttp://social.msdn.microsoft.com/Profile/en-US/?user=KristoferA%20-%20Huagati%20SystemsLINQ + .Contains(s) + sp_executesql = big performance problem<p> <div class=quote><font class=quoteHeader style=""> <table width="85%"> <tbody> <tr> <td class=txt4> <strong>Evaldas Jocys wrote:</strong></td></tr> <tr> <td class=quoteTable> <table width="100%"> <tbody> <tr> <td class=txt4 valign=top width="100%"><font size=2><span style="font-family:Arial">At this moment I have two incomplete solutions because both require </span></font><font size=2><span style="font-family:Arial">extension of current LINQ to SQL classes</span></font><font size=2><span style="font-family:Arial">:<br><br><span style="font-weight:bold">A)</span> Pass option WITH (INDEX = 0) to LINQ query (seems like there is no way to do that):<br></span></font><font size=2><span style="font-family:Arial"><span style="color:rgb(128,128,128)">(Submited by  Erland Sommarskog, SQL Server MVP, esquel@sommarskog.se)</span><br></span></font><font size=2><span style="font-family:Arial">This will force SQL server to use index scan so search will be multiple times faster.<br></span></font><br><font size=2><span style="font-family:Arial">exec sp_executesql N'SELECT Count(*) FROM dbo.TestTable1 <span style="color:rgb(0,128,0)">WITH (INDEX = 0)</span> WHERE [Name] LIKE @p0', N'@p0 nvarchar(9)', @p0='%pattern%'<br></span></font></td></tr></tbody></table></td></tr></tbody></table></div></span></font> <p></p> <p align=left><font size=2><span style="font-family:Arial"></span></font> </p> <p align=left><font size=2><span style="font-family:Arial">If I'm not mistaken, with (index=0) forces a table scan, not an index scan. If &quot;name&quot; was the primary clustered key this would effectively be the same but it is not in the example provided.</span></font></p> <p align=left><font size=2><span style="font-family:Arial"></span></font> </p> <p align=left><font size=2><span style="font-family:Arial"></span></font> </p><font size=2><span style="font-family:Arial"> <p align=left> <div class=quote><font class=quoteHeader style=""> <table width="85%"> <tbody> <tr> <td class=txt4> <strong>Evaldas Jocys wrote:</strong></td></tr> <tr> <td class=quoteTable> <table width="100%"> <tbody> <tr> <td class=txt4 valign=top width="100%"><br><span style="font-weight:bold">B)</span> Use SQL Full-Text extension to LINQ to SQL classes</span></font><font size=2><span style="font-family:Arial"> which doesn't exist. If extension exist then I can't find it on Google. </span></font><font size=2><span style="font-family:Arial">SQL </span></font>Full-Text <font size=2><span style="font-family:Arial"><span style="font-style:italic">CONTAINS(s)</span> would be enough.</span></font><br><font size=2><span style="font-family:Arial"><br>All I can do now is to extend command execution time by using <span style="font-style:italic">db.CommandTimeout = 120</span> when using search. It doesn't solve the performance problem but at least it it won't throw timeout error when using search.<br></span></font></td></tr></tbody></table></td></tr></tbody></table></div> <p></p> <p> </p> <p align=left>As I mentioned earlier, depending on what you store in the &quot;Name&quot; column this can be optimized using existing functionality. I'm assuming your real world usage of this is not 100x100 concatenated guids. If for example you're storing names, split it up into last/first/middle. If something else, create a child/lookup table with the data broken up into smaller units, e.g. sentence -&gt; words.</p> <p> </p> <p align=left>If you for some reason can not do any table layout changes to the database and/or if fulltext search is what you really need, encapsulate the fulltext lookup in a stored procedure that return PK values for the table you're searching in and then call that stored proc from L2S.    (But if you're storing/searching something like person names, then fulltext is overkill/unnecessary. Also don't forget that fulltext is not realtime in-sync with the db contents in the same way real db indexes are).</p></span></font>Mon, 10 Nov 2008 11:45:59 Z2008-12-01T22:59:31Zhttp://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/55ae6f5c-ddf2-4713-b3e2-f63278f60d7f#46221d2d-7b87-483d-828c-102657c727fehttp://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/55ae6f5c-ddf2-4713-b3e2-f63278f60d7f#46221d2d-7b87-483d-828c-102657c727feEvaldas Jocyshttp://social.msdn.microsoft.com/Profile/en-US/?user=Evaldas%20JocysLINQ + .Contains(s) + sp_executesql = big performance problem<div class=quote><font class=quoteHeader style=""> <table width="85%"> <tbody> <tr> <td class=txt4> <strong>KristoferA wrote:</strong></td></tr> <tr> <td class=quoteTable> <table width="100%"> <tbody> <tr> <td class=txt4 valign=top width="100%">If I'm not mistaken, with (index=0) forces a table scan, not an index scan. If &quot;name&quot; was the primary clustered key this would effectively be the same but it is not in the example provided.</td></tr></tbody></table></td></tr></tbody></table></div>You are right, its table scan (it runs faster than index seek). <div class=quote><font class=quoteHeader style=""> <table width="85%"> <tbody> <tr> <td class=txt4> <strong>KristoferA wrote:</strong></td></tr> <tr> <td class=quoteTable> <table width="100%"> <tbody> <tr> <td class=txt4 valign=top width="100%">If you for some reason can not do any table layout changes to the database and/or if fulltext search is what you really need, encapsulate the fulltext lookup in a stored procedure that return PK values for the table you're searching in and then call that stored proc from L2S.</td></tr></tbody></table></td></tr></tbody></table></div>This can solve problem. Unfortunately use of stored procedures defeats usefulness of LINQ because any SQL condition (WHERE, ORDER BY, ...) applied on Procedure results will be executed on client (C#) side and not on SQL server. I also want do search (.Where&lt;&gt;(x)) on LINQ queries defined before. <div class=quote><font class=quoteHeader style=""> <table width="85%"> <tbody> <tr> <td class=txt4> <strong>KristoferA wrote:</strong></td></tr> <tr> <td class=quoteTable> <table width="100%"> <tbody> <tr> <td class=txt4 valign=top width="100%">Also don't forget that fulltext is not realtime in-sync with the db contents in the same way real db indexes are</td></tr></tbody></table></td></tr></tbody></table></div>I could live with that because Full-Text index would be extremely usefull extension. <img height=19 alt=Smile src="http://forums.microsoft.com/MSDN/emoticons/emotion-1.gif" width=19>Mon, 10 Nov 2008 13:29:32 Z2008-11-10T13:29:32Z