I have a data structure that is basically a document with a dictionary of tags. I am attempting to bring back all documents of a given formtype that have a tag named 'Last Name' and a tag value of 'Smith'. There may be 0..N 'Last Name' tags associated with the document.
I am using the following linq query to try to match a source document to children with matching tags:
DB.Documents
.Where(doc => doc.FormID == pd.IndexForm.FormID)
.Where(doc => doc.Document_StringIndex_ReadOnly
.Join(Fields,
dsi => new { FieldName = dsi.FieldName, FieldValue = dsi.StringValue },
dsi2 => new { FieldName = dsi2.FieldName, FieldValue = dsi2.StringValue },
(dsi, dsi2) => dsi.Document).Count() > 0);
Which generates the following query when output using .ToTraceString()
SELECT
[Project1].*
FROM ( SELECT
[Extent1].*
(SELECT
COUNT(cast(1 as bit)) AS [A1]
FROM [dbo].[Document_StringIndex_ReadOnly] AS [Extent2]
INNER JOIN (SELECT [Extent3].*
FROM [dbo].[Document] AS [Extent3]
INNER JOIN [dbo].[Document_StringIndex_ReadOnly] AS [Extent4] ON [Extent3].[DocumentID] = [Extent4].[DocumentID] ) AS [Join1] ON (([Extent2].[FieldName] = [Join1].[FieldName]) OR (([Extent2].[FieldName] IS NULL) AND ([Join1].[FieldName] IS NULL))) AND (([Extent2].[StringValue] = [Join1].[StringValue]) OR (([Extent2].[StringValue] IS NULL) AND ([Join1].[StringValue] IS NULL)))
LEFT OUTER JOIN [dbo].[Document] AS [Extent5] ON [Extent2].[DocumentID] = [Extent5].[DocumentID]
WHERE ([Extent1].[DocumentID] = [Extent2].[DocumentID]) AND ([Join1].[DocumentID1] = @p__linq__7) AND ([Join1].[FieldName] = @p__linq__8)) AS [C1]
FROM [dbo].[Document] AS [Extent1]
WHERE [Extent1].[FormID] = @p__linq__5
) AS [Project1]
WHERE [Project1].[C1] > 0
If I do a direct substitution of constants for my parameters (as shown below) the query executes very quickly. However, if I leave the parameters in place the query takes several minutes.
SELECT
[Project1].*
FROM ( SELECT
[Extent1].*
(SELECT
COUNT(cast(1 as bit)) AS [A1]
FROM [dbo].[Document_StringIndex_ReadOnly] AS [Extent2]
INNER JOIN (SELECT [Extent3].*
FROM [dbo].[Document] AS [Extent3]
INNER JOIN [dbo].[Document_StringIndex_ReadOnly] AS [Extent4] ON [Extent3].[DocumentID] = [Extent4].[DocumentID] ) AS [Join1] ON (([Extent2].[FieldName] = [Join1].[FieldName]) OR (([Extent2].[FieldName] IS NULL) AND ([Join1].[FieldName] IS NULL))) AND (([Extent2].[StringValue] = [Join1].[StringValue]) OR (([Extent2].[StringValue] IS NULL) AND ([Join1].[StringValue] IS NULL)))
LEFT OUTER JOIN [dbo].[Document] AS [Extent5] ON [Extent2].[DocumentID] = [Extent5].[DocumentID]
WHERE ([Extent1].[DocumentID] = [Extent2].[DocumentID]) AND ([Join1].[DocumentID1] = 1015) AND ([Join1].[FieldName] = 'DDKey')) AS [C1]
FROM [dbo].[Document] AS [Extent1]
WHERE [Extent1].[FormID] = 22
) AS [Project1]
WHERE [Project1].[C1] > 0
After generating an execution plan, I learned that if I directly substitute the parameter values, SQL Server performs an index seek, and my query is fast. As soon as I leave the parameters in place, SQL Server will perform an index scan, and my query times out. Is there any way to prod SQL server to always seek? Can I force entity framework to not use parameterized queries?