2

У меня есть структура данных, которая в основном представляет собой документ со словарем тегов. Я пытаюсь вернуть все документы определенного типа формы, имеющие тег с именем «Фамилия» и значение тега «Смит». Там могут быть теги 0...N 'Last Name', связанные с документом.Оптимизация платформы Entity Framework Сгенерированный план выполнения SQL Server

Я использую следующий запрос Linq, чтобы попытаться соответствовать исходный документ для детей с соответствующими тегами:

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); 

который генерирует следующий запрос при выводе с использованием .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 

Если я выполняю прямую подстановку констант для моих параметров (как показано ниже), запрос выполняется очень быстро. Однако, если оставить параметры на месте, запрос занимает несколько минут.

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 

После создания плана выполнения, я узнал, что, если я сразу подставлять значение параметров, SQL Server выполняет поиск по индексу, и мой запрос быстро. Как только я оставлю параметры на месте, SQL Server выполнит сканирование индекса, а мой запрос истечет. Есть ли способ заставить SQL-сервер всегда искать? Могу ли я заставить сущность framework не использовать параметризованные запросы?

+0

Какую версию Linq для Entities вы используете? – Phil

ответ

4

В сгенерированном SQL, эта линия

[Join1].[FieldName] = @p__linq__8 

может быть проблемой.

Если FieldName является varchar(...) и @p__linq__8 является nvarchar(...), то это положение будет вызывать сканирование таблицы, так как тип параметра не совпадает с типом индекса.

Когда вы напрямую подменяете «DDKey», типы соответствуют, чтобы получить индексный поиск. Попробуйте выполнить запрос с помощью N'DDkey и посмотрите, есть ли у вас сканирование таблицы.

Это проблема с различными версиями Linq to Sql и Linq to Entities, но может быть исправлена ​​в последующих выпусках.

Один из способов обойти проблему, если вы не можете обновить до последней версии, - это изменить FieldName на nvarchar(...).

+0

Спасибо. Изменение параметров в varchar создает правильный план выполнения. Потребуется некоторое время, чтобы перестроить таблицу и индексы с помощью типов столбцов nvarchar, но похоже, что это была моя проблема. – user1431334

Смежные вопросы