2015-06-17 2 views
3

Я делаю вызов к внешней базе данных за пределами моей локальной сети, однако запрос занимает 40 секунд, чтобы закончить ..LINQ принимает 40s для завершения запроса - Производительность

я делаю вызов с помощью EDMX.

String Example = "Example"; 
var Result = EDMXEntity.Entities 
    .Where(
     x => 
     (
      x.Name.ToString().ToLower().Contains(Example.ToLower()) 
     )) 
    .Take(50) 
    .ToList(); 

текущий код благодаря Szer:

var Result = EDMXEntity.Entities.Where(x => SqlFunctions.PatIndex(x.Name.ToString().ToLower(), Example.ToLower()) > 0).Take(50).ToList(); 
+1

ваш 'IQueryable' преобразует в' ВЫБРАТЬ TOP 50 * FROM [Extent1 ] WHERE (CAST (CHARINDEX (LOWER (@ p__linq__0), LOWER (CASE WHEN ([Extent1]. [Name] IS NULL) THEN N '' ELSE [Extent1]. [Name] END)) AS INT))> 0' , Вероятно, где предложение является причиной отставания – Szer

+1

Есть ли у вас вопрос о том, как улучшить производительность? – neverendingqs

+0

@Szer да запрос преобразуется в это, то, что я хотел, было похоже на select * from Entities Где ниже (Name), например '% Example%', выполнение этого запроса в студии управления SqlServer занимает ~ 1 с – BrunoMartinsPro

ответ

1

Late ответьте на мой комментарий выше:

Проблема в том, что вы загружаете все сущности из БД мне mory и фильтрацию на вашей машине. Вы должны отфильтровать свой запрос раньше с помощью вашего механизма БД.

Для этого вы должны использовать SqlFunctions, которые сопоставляются с прямым кодом T-SQL поставщиком LINQ SQL. В вашем случае вы можете заменить string.Contains() на SqlFunctions.PatIndex, который почти такой же (она возвращает int вместо bool)

Как это:

var result = EDMXEntity.Entities 
    .Where(x => SqlFunctions.PatIndex(
     stringPattern: x.Name.ToString().ToLower(), 
     target:  Example.ToLower()) > 0) 
    .Take(50) 
    .ToList(); 
1

SQL Studio управления сервером делает его менее чем за секунду

Скорее всего, это вызвано плохим запросом кэшированные план выполнения, как описано here, here и here.

Люди обнаружили, что выполнение следующих команд в SQL Server устраняет эту проблему для них. (Вполне возможно, что только вторая команда действительно необходима.)

DBCC DROPCLEANBUFFERS 
DBCC FREEPROCCACHE 
1

Вашим лучшим выбором для сравнения строк будет использовать случай неравенство, так что вам не придется иметь дело с преобразовательными строками. В этом случае .ToString на имени не является действительно необходимым, я не думаю (опять же, я не уверен, как он хранится, поэтому он может понадобиться). Также с именем вы можете попробовать использовать равенство или по крайней мере

Наконец, вы можете попробовать разделить его на объект Queryable и выполнить запрос таким образом. Таким образом, вы можете сократить количество ресурсов, используемых для самого запроса.

Редактировать

Поскольку это не желательно, чтобы проверить со всей строкой, вы можете использовать IndexOf вместо того, чтобы не использовать полные строки

Смотрите следующее:

String Example = "Example"; 
var EDMXEntity = new List<String>(); 
var Query = EDMXEntity.Entities.AsQueryable(); 
var Result = Query 
    .Where(
     x => 
     (
      x.Name.ToString().ToLower().Contains(Example.ToLower()) 
     )) 
    .Take(50) 
    .ToList(); 
+0

Dylan, проблема с этим подходом заключается в том, что запрос ожидает полных строк, если имя пользователя «Джон», если вы ищете «Joh», вы не получите никаких данных, вот почему (благодаря @Szer) Я использовал SqlFunctions.PatIndex («%» + Example.ToLower() + «%», x.Name.ToString(). ToLower())> 0, но поскольку вы будете запускать запрос только тогда, когда вы это сделаете. ToList() может быть быстрее. – BrunoMartinsPro

+1

@ Lightwalker Я обновил свой код с лучшей реализацией (тот, который будет не просто использовать полные строки) –

+0

linq выдает ошибку ... «LINQ to Entities не распознает метод« Int32 IndexOf (System.String, System. StringComparison) ', и этот метод не может быть переведен в выражение хранилища. " – BrunoMartinsPro

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