Sql server SQL Server中LIKE命令的问题

Sql server SQL Server中LIKE命令的问题,sql-server,sql-server-2008,Sql Server,Sql Server 2008,我正在尝试执行一个包含SQL Server 2008数据库中的LIKE的查询,但由于某些原因,该查询会花费很长时间并超时 该表包含大约4700万行的聚合日志数据,我试图为包含特定应用程序名称的特定计算机找到一个日志条目。我的查询如下所示: SELECT MgmtLogID,MgmtLogSeverity, MgmtLogSource, CAST(MgmtLogText as TEXT) as MgmtLogText, MgmtLogTime, MgmtLogHost FROM [dbo].

我正在尝试执行一个包含SQL Server 2008数据库中的LIKE的查询,但由于某些原因,该查询会花费很长时间并超时

该表包含大约4700万行的聚合日志数据,我试图为包含特定应用程序名称的特定计算机找到一个日志条目。我的查询如下所示:

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
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%'
选择MgmtLogID、MgmtLogSeverity、MgmtLogSource、CAST(MgmtLogText作为文本)作为MgmtLogText、MgmtLogTime、MgmtLogHost
来自[dbo]。[MgmtLog]
--固定值

其中MgmtLogOrigin='EventLog'和MgmtLogSeverity像
这样的查询子句,像“%something%”这样的colname不能利用索引,通常会导致对可能的行进行完整扫描,以确定应该传递哪些行

尽管,正如ChrisC在评论中指出的,令人有些惊讶的是,在尝试使用
like
之前,没有首先使用更高效的子句将候选行集缩减到可管理的大小-可能表的统计信息不够最新,查询分析无法确定这一点-最好在SQL下运行
解释查询的任何重要信息服务器

非like查询之所以如此快速,是因为它几乎肯定在
MgmtLogHost
和/或
MgmtLogTime
上有一个索引,可以用来快速剔除不需要的行

解决此问题的一种方法是,仅在更改时使用插入/更新触发器来处理
MgmtLogText
数据,将应用程序名称提取出来,并将其放在一个单独的表中,这样可以更好地进行优化

即使只是使用这样一个触发器来保持该列的小写版本(在另一列中),也将是一种改进。使用不区分大小写的排序意味着选择运行较慢,因为它们必须允许将
xyzy
xyzy
归类为相等。相反,如果您在表中维护小写版本,并确保按照小写进行检查,那么这种努力就会消失,因为您只需要担心一个案例

而且,通过在触发器中执行所有这些操作,您可以确保仅在必要时(当数据发生更改时)才执行这些操作,而不是每次选择时都执行这些操作。这将在多个选择上摊销成本

如果你的DBMS支持,你也可以使用全文索引,但我经常认为这就像用热核弹头杀死蚊子一样


是的,在某些情况下,您可能需要全文索引,但在绝大多数情况下,您可以通过更具选择性来提高效率。

这样的查询子句,其中像“%something%”这样的colname不能利用索引,通常会导致对可能的行进行完整扫描,以确定应该传递哪些行

尽管,正如ChrisC在评论中指出的,令人有些惊讶的是,在尝试使用
like
之前,没有首先使用更高效的子句将候选行集缩减到可管理的大小-可能表的统计信息不够最新,查询分析无法确定这一点-最好在SQL下运行
解释查询的任何重要信息服务器

非like查询之所以如此快速,是因为它几乎肯定在
MgmtLogHost
和/或
MgmtLogTime
上有一个索引,可以用来快速剔除不需要的行

解决此问题的一种方法是,仅在更改时使用插入/更新触发器来处理
MgmtLogText
数据,将应用程序名称提取出来,并将其放在一个单独的表中,这样可以更好地进行优化

即使只是使用这样一个触发器来保持该列的小写版本(在另一列中),也将是一种改进。使用不区分大小写的排序意味着选择运行较慢,因为它们必须允许将
xyzy
xyzy
归类为相等。相反,如果您在表中维护小写版本,并确保按照小写进行检查,那么这种努力就会消失,因为您只需要担心一个案例

而且,通过在触发器中执行所有这些操作,您可以确保仅在必要时(当数据发生更改时)才执行这些操作,而不是每次选择时都执行这些操作。这将在多个选择上摊销成本

如果你的DBMS支持,你也可以使用全文索引,但我经常认为这就像用热核弹头杀死蚊子一样


是的,在某些情况下,您可能需要全文索引,但在绝大多数情况下,您可以通过选择多一点来提高效率。

根据MgmtLogText的字段类型,不会使用索引。此外,正如其他评论者所提到的那样,LIKE还阻止使用索引

我不知道如果使用子查询是否有效。内部查询应该是不带LIKE的查询,它只返回10个结果。那么外部查询应该是使用LIKE的查询。这样,类似的搜索只需搜索10行,而不是4700万行

也许有一种更有效的方法,但我想的是:

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
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%'
选择MgmtLogID、MgmtLogSeverity、MgmtLogSource、CAST(MgmtLogText作为文本)作为MgmtLogText、MgmtLogTime、MgmtLogHost
来自[dbo]。[MgmtLog]
MgmtLogID在哪里(
选择MgmtLogID
从[dbo.MgmtLog]
其中MgmtLogOrigin='EventLog'和MgmtLogSeverity'MY START TIME'
按MgmtLogTime DESC订购
)
和MgmtLogText,如“%some value%”

根据MgmtLogText的字段类型,不会使用索引。此外,正如其他评论者所提到的那样,LIKE还阻止使用索引

我不知道如果使用子查询是否有效。内部查询应该是不带LIKE的查询,它只返回10个结果。那么外部查询应该是