我正在尝试在SQL Server 2008数据库中执行包含LIKE的查询,但由于某种原因,查询会花费很长时间并超时。
该表包含大约4700万行,其中包含聚合日志数据,我正在尝试查找包含特定应用程序名称的特定计算机的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
查询在没有LIKE的情况下在大约1-2秒内执行,并返回大约10行。使用LIKE,它应该返回那10个中的2行,所以它不应该是那个征税但它会超时。我猜它与MgmLogText的属性有关,但我不确定是什么。它是ntext
字段,长度为16,使用Finnish_Swedish_CI_AS排序规则。
最后我需要从php脚本执行查询,因为我需要查找任意数量的机器和/或应用程序的日志记录
答案 0 :(得分:2)
根据MgmtLogText的字段类型,将不使用索引。此外,正如其他评论者所提到的,LIKE也阻止了索引的使用。
在我的脑海中,我想知道如果使用子查询它是否会起作用。内部查询应该是没有LIKE的查询,只返回10个结果。然后外部查询应该是使用LIKE的查询。这样,LIKE只需要搜索10行而不是4700行。
可能有一种更有效的方式,但我在考虑这样的事情:
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 :(得分:1)
像where colname like '%something%'
这样的查询子句无法利用索引,并且通常会对可能的行进行全面扫描,以确定应该传递哪些行
尽管正如ChrisC在评论中所指出的那样,在尝试使用like
之前,更有效的条款并没有用于将候选行集减少到可管理的大小,这有点令人惊讶 - 也许是该表不是最新的,以便查询分析决定这一点 - 最好运行SQL Server下explain query
的任何计数。
你的非同类查询如此之快的原因是因为它几乎肯定有一个MgmtLogHost
和/或MgmtLogTime
的索引,可以用来快速剔除不需要的行。
您可以通过一种方式解决此问题,即使用插入/更新触发器等方法仅在更改时处理MgmtLogText
数据,以提取应用程序名称并将它们单独放入表可以更好地优化。
即使只使用这样的触发器来保持列的小型版本(在另一个列中)也会有所改进。使用不区分大小写的排序规则意味着选择运行较慢,因为它们必须允许XYZZY
和xyzzy
被归类为相等。相反,如果您在表格中维护一个较低版本的版本并确保对小写字母进行检查,那么这种努力就会消失,因为您只需要担心一个案例。
并且,通过在触发器中完成所有这些操作,您可以确保仅在必要时(数据更改时)完成,而不是每次都要选择。这使得成本高于许多选择。
如果你的DBMS支持它,你也可以使用像全文索引这样的东西,但我常常认为这就像试图用热核弹头杀死蚊子一样。
是的,在某些情况下您可能需要全文索引,但在绝大多数情况下,您可以通过提高选择性来提高效率。