LinqToSql. Содержит и параметры nvarchar vs varchar -> план конверсии индекса - PullRequest
5 голосов
/ 21 ноября 2008

У меня есть только одна таблица, сопоставленная в текстовом формате. Вот свойство и атрибут интересующей колонки:

[Column(Storage="_CustomerNumber", DbType="VarChar(25)")]
public string CustomerNumber
{

Этот столбец фактически является varchar (25) и имеет индекс.

У меня есть простой код:

DataClasses1DataContext myDC = new DataClasses1DataContext();
myDC.Log = Console.Out;

List<string> myList = new List<string>() { "111", "222", "333" };
myDC.Customers
    .Where(c => myList.Contains(c.CustomerNumber))
    .ToList();

, который генерирует этот текст SQL:

SELECT [t0].[CustomerNumber], [t0].[CustomerName]
FROM [dbo].[Customers] AS [t0]
WHERE [t0].[CustomerNumber] IN (@p0, @p1, @p2)
-- @p0: Input NVarChar (Size = 3; Prec = 0; Scale = 0) [111]
-- @p1: Input NVarChar (Size = 3; Prec = 0; Scale = 0) [222]
-- @p2: Input NVarChar (Size = 3; Prec = 0; Scale = 0) [333]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8

Обратите внимание, что параметры являются nvarchar!

Когда этот запрос попадает в базу данных, он генерирует ужасный план, который включает преобразование многомиллионного индекса строки в CustomerNumber в nvarchar перед поиском в нем.

Мне не разрешено менять таблицу, но я могу изменить запрос и dbml. Что я могу сделать, чтобы получить данные без преобразования индекса?

Ответы [ 3 ]

3 голосов
/ 10 ноября 2010

Вот как я решаю эту проблему сейчас. Это преобразует параметры в нужный тип, а затем запускает запрос. Он генерирует тот же sql, что и изначально, только с разными типами параметров.

DbCommand myCommand = myDataContext.GetCommand(query);

foreach (DbParameter dbParameter in myCommand.Parameters)
{
  if (dbParameter.DbType == System.Data.DbType.String)
  {
    dbParameter.DbType = System.Data.DbType.AnsiString;
  }
}    

myDataContext.Connection.Open();

System.Data.Common.DbDataReader reader = myCommand.ExecuteReader();
List<RecordType> result = myDataContext.Translate<RecordType>(reader).ToList();

myDataContext.Connection.Close();
0 голосов
/ 09 сентября 2013

Для проекта, над которым я работаю, мы должны использовать ObjectContext вместо DbContext, поэтому у меня нет готового доступа к GetCommand() или DbParameters. Что я делаю, так это преобразовываю запрос в строку, удаляю в запросе индикатор NVARCHAR, затем выполняю запрос к ObjectContext. Вот подробная реализация для данного примера:

List<string> myList = new List<string>() { "111", "222", "333" };

IQueryable<Customers> badQuery =  myDC.Customers
    .Where(c => myList.Contains(c.CustomerNumber));

string query = ((System.Data.Objects.ObjectQuery)badQuery).ToTraceString();
query = query.Replace(",N'", ",'").Replace("(N'","('");

List<Customers> customers = myDC.ExecuteStoreQuery<Customers>(query).ToList();
0 голосов
/ 21 ноября 2008

Вот что у меня есть как обходной путь. Мне интересно посмотреть и на другие решения:

List<IQueryable<Customer>> myQueries = 
    myList.Select(s => myDC.Customers.Where(c => c.CustomerNumber == s)).ToList();
IQueryable<Customers> myQuery = myQueries.First();
foreach(IQueryable<Customer> someQuery in myQueries.Skip(1))
{
    myQuery = myQuery.Concat(someQuery);
}
myQuery.ToList();

Это генерирует следующий SQL:

SELECT [t4].[CustomerNumber], [t4].[CustomerName]
FROM (
    SELECT [t2].[CustomerNumber], [t2].[CustomerName]
    FROM (
        SELECT [t0].[CustomerNumber], [t0].[CustomerName]
        FROM [dbo].[Customer] AS [t0]
        WHERE [t0].[CustomerNumber] = @p0
        UNION ALL
        SELECT [t1].[CustomerNumber], [t1].[CustomerName]
        FROM [dbo].[Customer] AS [t1]
        WHERE [t1].[CustomerNumber] = @p1
        ) AS [t2]
    UNION ALL
    SELECT [t3].[CustomerNumber], [t3].[CustomerName]
    FROM [dbo].[Customer] AS [t3]
    WHERE [t3].[CustomerNumber] = @p2
    ) AS [t4]
-- @p0: Input VarChar (Size = 3; Prec = 0; Scale = 0) [111]
-- @p1: Input VarChar (Size = 3; Prec = 0; Scale = 0) [222]
-- @p2: Input VarChar (Size = 3; Prec = 0; Scale = 0) [333]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...