-3

如果我检查 [deliverybody] 字段是否包含“x”,则第一个/未缓存的查询需要很长时间,以消除带有“x”的行。如果我不检查“x”,[deliverytime] 会被索引并在一秒钟内完成查询。

使用AND [deliverybody] <> 'x'部分,查询执行时间为 10+ 秒,没有;1秒。似乎索引字段 [deliverytime] 不会有太大帮助。

查询只返回 1600 行。扫描额外的 1600 个字段需要 10 多秒。查询有什么问题?

更新:从 NTEXT 升级到 NVARCHAR(MAX)。内部查询的执行计划:

此查询需要 10 多秒:

  SELECT MAX([deliveryid]) AS deliveryid, COUNT(*) AS cnt  
  FROM [_hMaiServer].[dbo].[hm_deliverylog]
  WHERE [deliverytime] > DATEADD(HOUR, -24, GETDATE()) 
  AND [deliverybody] <> 'x' 
  GROUP BY deliverysubject

查询在一秒钟内完成:

SELECT MAX([deliveryid]) AS deliveryid, COUNT(*) AS cnt  
FROM [_hMaiServer].[dbo].[hm_deliverylog]
WHERE [deliverytime] > DATEADD(HOUR, -2400, GETDATE()) 
--AND [deliverybody] <> 'x' 
GROUP BY deliverysubject

以及带有索引的表结构:http: //pastebin.com/W0PsDnqS

我的结论:

检查 5000 行需要 10 多秒。较小的{HOUR}值使执行时间更快。如果这没问题,这没问题,但对我来说似乎很慢。

SELECT COUNT(*) FROM [hm_deliverylog]
WHERE [deliverybody] <> 'x' 
AND [deliverytime] > DATEADD(HOUR, -__{HOUR}__ , GETDATE())     
4

1 回答 1

1

您尚未提供要求的SET STATISTICS IO ON;结果。

然而,一种可能的改进可能是而不是使用

WHERE [deliverybody] <> 'x'

使用

WHERE NOT (LEN([deliverybody]) = 1 AND LEFT([deliverybody],1) = 'X')

下面是一个有益的示例。

CREATE TABLE T1
  (
     Id             INT,
     [deliverybody] VARCHAR(MAX)
  )

INSERT INTO T1
VALUES     (1, Replicate(Cast('A' AS VARCHAR(MAX)), 2000000000)),
           (2,'X')

SET STATISTICS IO ON;

SELECT id
FROM   T1
WHERE  NOT ( Len([deliverybody]) = 1
             AND LEFT([deliverybody], 1) = 'X' )

SELECT id
FROM   T1
WHERE  [deliverybody] <> 'X'

DROP TABLE T1 

两者的 IO 结果如下

Table 'T1'. Scan count 1, logical reads 1, physical reads 0, read-ahead reads 0
            , lob logical reads 6, lob physical reads 0, lob read-ahead reads 0.

Table 'T1'. Scan count 1, logical reads 1, physical reads 0, read-ahead reads 0
    lob logical reads 2209665, lob physical reads 0, lob read-ahead reads 642255.

第一个读取次数明显减少,因为它避免拖出整个 2GB 值以发现它不是X

于 2012-11-13T21:41:00.397 回答