有索引时为什么查询运行如此缓慢?

时间:2018-08-14 15:12:01

标签: sql sql-server indexing

我正在SQL Server中运行查询,但突然开始运行非常慢。直到昨天,它过去的运行时间均不到1秒(或最多3秒)。突然之间,今天需要7到9分钟。我相信我的索引设置正确。

这是表的定义:

CREATE TABLE T_INDEX (
    IndexId INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    [OwnerId] [varchar](20) NOT NULL DEFAULT (0),
    [TicketId] [int] NOT NULL DEFAULT (0),
    [TicketLogId] [int] NOT NULL DEFAULT (0),
    [Type] [varchar](20) NOT NULL DEFAULT (''),
    [CallId] [varchar](30) NULL,
    [MessageId] [varchar](30) NULL,
    [IndexRawDataId] [int] NOT NULL DEFAULT (0),
    --INDEX/SEARCH
    [CallTime] [datetime] NOT NULL,
    [IndexMessageId] [int] NOT NULL DEFAULT (0),
    [Direction] [varchar](20) NULL,
    [Action] [varchar](20) NULL,
    [Result] [varchar](30) NULL,
    --GENERAL
    [DefaultFileName] [varchar](100) NOT NULL DEFAULT '',
    [TimeElapsedForTransfer] [int] NOT NULL DEFAULT (0),
    [TimeElapsedForIndex] [int] NOT NULL DEFAULT (0),
    [Duration] [int] NULL,
    [HasR] [bit] NOT NULL DEFAULT (0), -- HAS RECORDING
    [HasV] [bit] NOT NULL DEFAULT (0), -- HAS VOICEMAIL
    [DeletedInd] [bit] NOT NULL DEFAULT (0),
    [CompleteInd] [bit] NOT NULL DEFAULT (0)
)

我有这样定义的索引:

CREATE INDEX idx__T_INDEX__CallId
  ON RingClone.dbo.T_INDEX (CallId)
GO

CREATE INDEX idx__T_INDEX__CallTime
  ON RingClone.dbo.T_INDEX (CallTime)
GO

CREATE INDEX idx__T_INDEX__MessageId
  ON RingClone.dbo.T_INDEX (MessageId)
GO

CREATE INDEX idx__T_INDEX__OwnerId
  ON RingClone.dbo.T_INDEX (OwnerId)
GO

CREATE INDEX idx_T_INDEX_Dist
  ON RingClone.dbo.T_INDEX (CompleteInd, DeletedInd)
  INCLUDE (CallId, MessageId, OwnerId)
GO

CREATE INDEX nci_wi_T_INDEX_4E1CEC32C8F3DA763461240A854A7891
  ON RingClone.dbo.T_INDEX (TicketId)
GO

我的查询如下:

DECLARE @ownerId varchar(20)
DECLARE @type varchar(20)
DECLARE @dateFrom datetime
DECLARE @dateTo datetime

SELECT TOP 50 T_INDEX.*
    FROM T_INDEX
    WHERE OwnerId=@ownerId
     AND [Type]=@type
     AND CallTime >= @dateFrom
     AND CallTime <= @dateTo
    ORDER BY CallTime DESC

此表中大约有400万条记录。并且该表的所有索引上的碎片小于2%。在发现速度缓慢之前,我刚刚更新了约5万行(更改了OwnerId)。但是之后我立即重新索引了索引。此更新可能与突然的缓慢有关吗?我是否为此查询正确设置了索引?如果我将OwnerId,'Type , and 'CallTime组合在一起,是否会使查询运行得更快?还有什么我可以做的才能使它快速运行?

2 个答案:

答案 0 :(得分:2)

  

AND(@dateFrom IS为NULL或CallTime> = @dateFrom)

请进行适当的查询-@dateFrom是否为null。动态生成SQL。

可替代地将查询优化为未知。

您轻而易举地遇到了一次参数嗅探,即一次确定查询计划并重新使用查询计划的情况。并且当其他查询计划更有意义时不会更新。

https://www.brentozar.com/archive/2013/06/the-elephant-and-the-mouse-or-parameter-sniffing-in-sql-server/

答案 1 :(得分:-1)

对于此查询:

SELECT TOP 50 T_INDEX.*
FROM T_INDEX
WHERE OwnerId = @ownerId AND
     [Type] = @type AND
     CallTime >= @dateFrom AND
     CallTime <= @dateTo
ORDER BY CallTime DESC;

最佳索引是(OwnerId, Type, CallTime)上的综合索引。前两列可以互换。

对于查询,您只有两个候选索引:(OwnerId)(CallTime)(尽管SQL Server可能无法捕获该索引)。都不是最佳选择。

另一个潜在的问题是执行计划可能会被缓存。例如,如果代码在存储过程中,并且该过程在空表上进行了测试,则它可能不使用索引来缓存执行计划。这就是为什么with (recompile)通常用于存储过程中的查询。