Проблемы с командой LIKE в SQL Server - PullRequest
0 голосов
/ 24 ноября 2011

Я пытаюсь выполнить запрос, содержащий LIKE, в базе данных SQL Server 2008, но по какой-то причине запрос выполняется вечно и время ожидания.

Таблица содержит около 47 миллионов строк с агрегированными данными журнала,и я пытаюсь найти logentry для конкретной машины, содержащей конкретное имя приложения.Мой запрос выглядит так:

SELECT MgmtLogID,MgmtLogSeverity, MgmtLogSource, CAST(MgmtLogText as TEXT) as MgmtLogText,   MgmtLogTime, MgmtLogHost 
FROM [dbo].[MgmtLog] 
--Fixed values
WHERE MgmtLogOrigin = 'EventLog' AND MgmtLogSeverity <= 3 
--Values depending on what I'm searching for
AND MgmtLogHost = 'MY MACHINENAME'AND MgmtLogTime > 'MY START TIME' AND MgmtLogText LIKE '% KEYWORD TO SEARCH FOR %' 
ORDER BY MgmtLogTime DESC

Запрос выполняется за 1-2 секунды без LIKE и возвращает около 10 строк.С LIKE он должен возвратить 2 строки из этих десяти, так что это не должно облагаться налогом, но время ожидания истекло.Я предполагаю, что это как-то связано со свойствами MgmLogText, но я не уверен, что.Это поле ntext длиной 16 с использованием сортировки Finnish_Swedish_CI_AS.

В конце мне нужно выполнить запрос из сценария php, так как мне нужно найти записи журнала для произвольного числа машин и /или приложения

Ответы [ 2 ]

2 голосов
/ 24 ноября 2011

В зависимости от типа поля MgmtLogText индексы не будут использоваться.Кроме того, как уже упоминалось другими комментаторами, LIKE также не позволяет использовать индекс.

Вверху моей головы, интересно, сработает ли это, если вы используете подзапрос.Внутренний запрос должен быть без запроса LIKE, который возвращает только 10 результатов.Тогда внешний запрос должен быть тем, который использует LIKE.Таким образом, LIKE должен искать только в 10 строках вместо 47 миллионов.

Возможно, есть более эффективный способ, но я подумал примерно так:

SELECT MgmtLogID,MgmtLogSeverity, MgmtLogSource, CAST(MgmtLogText as TEXT) as MgmtLogText,   MgmtLogTime, MgmtLogHost 
FROM [dbo].[MgmtLog] 
WHERE MgmtLogID IN (
  SELECT MgmtLogID
  FROM [dbo.MgmtLog]
  WHERE MgmtLogOrigin = 'EventLog' AND MgmtLogSeverity <= 3 
  AND MgmtLogHost = 'MY MACHINENAME'AND MgmtLogTime > 'MY START TIME'
  ORDER BY MgmtLogTime DESC
)
AND MgmtLogText LIKE '%some value%'
1 голос
/ 24 ноября 2011

Предложения запроса, такие как where colname like '%something%', не могут использовать индексы и обычно приводят к полному сканированию возможных строк, чтобы определить, какие из них должны быть доставлены

Хотя, как указывает ChrisC в комментарииНесколько удивительно, что более эффективные предложения не используются для уменьшения набора строк-кандидатов до приемлемого размера, прежде чем пытаться использовать like - возможно, статистика для таблицы недостаточно актуальна для анализа запроса, чтобы принять решениеэто - лучше всего запускать то, что считается для explain query под SQL Server.

Причина, по которой ваш непохожий запрос настолько быстр, состоит в том, что он почти наверняка имеет индекс на MgmtLogHost и / или MgmtLogTime, которыйможет использоваться для быстрого отбрасывания ненужных строк.

Один способ, которым вы можете это исправить, - использовать что-то вроде триггеров вставки / обновления для обработки данных MgmtLogText только после изменения, чтобы извлечьимена приложений и поместите их в отдельную таблицу, которая может быть намного лучше оптимизирована.

Даже просто используя such триггер для сохранения версии столбца в нижнем регистре (в другом столбце ) будет улучшением.Использование сортировки без учета регистра означает, что выборки выполняются медленнее, поскольку они должны учитывать классы XYZZY и xyzzy как равные.Если вместо этого вы сохраняете версию в нижнем регистре в таблице и проверяете, выполняется ли проверка в нижнем регистре, это усилие исчезает, так как вам остается беспокоиться только об одном случае.

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

Вы также можете использовать что-то вроде полнотекстового индексирования, если ваша СУБД поддерживает это, но я часто думал, что это похоже на попытку убить комаров с помощью термоядерной боеголовки.

Да, существуют ситуации, когда вам может понадобиться полнотекстовая индексация, но в подавляющем большинстве случаев вы можете повысить эффективность, немного более избирательно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...