如何加快非索引列SQL上的查询

时间:2016-06-03 21:31:36

标签: sql sql-server

我有一个包含大约3亿行的错误日志表。 Date列上有一个索引,但我试图通过日期和错误消息进行查询。当我按日期查询时它很快但我需要按消息查询,这会减慢它的速度。

我的查询如下

WITH data_cte(errorhour, message) 
     AS (SELECT Datepart(hh, date) AS ErrorDay, 
                message 
         FROM   cloud.errorlog 
         WHERE  date <= '2016-06-02' 
           AND  date >= '2016-06-01') 
SELECT errorhour, 
       Count(*) AS count, 
       message 
FROM   data_cte 
WHERE  message = 'error connecting to the server' 
GROUP  BY errorhour 
ORDER  BY errorhour 

添加where子句会降低速度,因为Message未编入索引。我怎样才能加快速度?

编辑:我无法在Message上编制索引,因为它定义为varchar(max)

4 个答案:

答案 0 :(得分:2)

只需为<line><e></e></line> <line><e><e></e></e></line> <line><e><e></e><e></e></e></line> 创建一个复合索引并过滤内部cte,而不是在外部。

(date, message)

答案 1 :(得分:1)

如果您始终正在搜索文本'error connecting to the server',那么您可以使用过滤的索引:

CREATE INDEX ix_ectts ON ErrorLog (Date) 
   WHERE (Date between '2016-06-01' and '2016-06-02')
     AND Message='error connecting to the server';

此索引的字节数应相当小,并且可以快速查阅。 然而,更新可能相当慢;考虑每次需要运行此查询并在之后删除它时创建它。

另一个选择是use a computed column on the first few hundred characters of Message, and index on that

ALTER TABLE ErrorLog
   ADD Message_index AS (cast (Message as varchar(400)));

CREATE INDEX theIndex ON ErrorLog (Message_index, [date]);

编辑:投射后添加了缺少的括号

答案 2 :(得分:0)

您可以将查询简化为:

     SELECT Datepart(day, date) AS ErrorDay, datepart(hour, date) as ErrorHour
            count(*) 
     FROM cloud.errorlog 
     WHERE date <= '2016-06-02' AND  date >= '2016-06-01') AND
           message = 'error connecting to the server'
     GROUP BY Datepart(day, date), datepart(hour, date);

然后,对于此查询,您需要errorlog(message, date)上的索引。由于相等比较,message在索引中排在第一位是很重要的。

编辑:

如果消息太长而您想要这样的查询,我建议添加一个计算列并将其用于索引和where子句:

alter table errlog add message250 as (left(message, 250));

create index idx_errlog_message250_date on (message250, date);

然后将查询写为:

     SELECT Datepart(day, date) AS ErrorDay, datepart(hour, date) as ErrorHour
            count(*) 
     FROM cloud.errorlog 
     WHERE date <= '2016-06-02' AND  date >= '2016-06-01') AND
           message250 = 'error connecting to the server'
     GROUP BY Datepart(day, date), datepart(hour, date);

答案 3 :(得分:0)

如果可以提取错误消息的简短摘要,那么您可以在INSERT中将其包含在日志中,并将其包含在error_summary新列中,您可以对其进行索引并在SELECT中使用它。

您解析完整的错误消息并删除时间戳,用户ID和特定内容,例如服务器名称和堆栈跟踪。如果没有明确的解析,请将error_summary保留为null。然后,您可以在error_summary上进行初步搜索,如果失败则返回Message搜索。