Sql 有索引时,为什么查询运行得这么慢?

Sql 有索引时,为什么查询运行得这么慢?,sql,sql-server,indexing,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 NU

我正在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
DECLARE@ownerId varchar(20)
声明@type varchar(20)
声明@dateFrom datetime
声明@DateToDateTime
选择前50个T_索引*
从T_指数
其中OwnerId=@OwnerId
和[Type]=@Type
和CallTime>=@dateFrom
和CallTime用于此查询:

SELECT TOP 50 T_INDEX.*
FROM T_INDEX
WHERE OwnerId = @ownerId AND
     [Type] = @type AND
     CallTime >= @dateFrom AND
     CallTime <= @dateTo
ORDER BY CallTime DESC;
选择前50个T\u索引*
从T_指数
其中OwnerId=@OwnerId和
[类型]=@类型和
CallTime>=@dateFrom和
通话时间
和(@dateFrom为NULL或CallTime>=@dateFrom)

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

或者将查询标记为“未知优化”

在这里,查询计划只需确定一次,就可以重用,这就是所谓的参数嗅探。当不同的查询计划更有意义时,不会更新


enterprise manager中的“显示查询计划”显示了什么?这看起来像一个“全面”查询;它们的速度是出了名的慢。盖尔·肖(Gail Shaw)在这方面做了一篇出色的文章:此外,您的
排名也很靠前,但您的
订单在哪里?谢谢您的反馈。没有空的日期范围,所以我选择了“空检查”。此外,我错误地漏掉了
orderby
子句,因此我将其重新添加到问题中。然而,即使去掉了“包罗万象”,它仍然可以运行7-9分钟。开始重构吧。类型是一个varchar-它应该是一个带有单独查找表的int。Varchar比较总是比其他任何东西都慢得多,我认为您需要一个Varchar(20)来编写所有可能的代码。和其他数据一样,空间和操作使用率看起来是一个非常糟糕的设计。。。。陛下可能存在的null或not null的组合。@TomTom。我不知道你指的是什么。这正是OP指定的查询,它只对日期范围进行
NULL
检查。我相信TomTom想说的是,Gordon,SQL Server在提供可为NULL的参数时会表现得非常糟糕,特别是在存在多个参数的情况下。因此,由于
@dateFrom
@dateTo
都有可能为
NULL
,这可能会对查询估计器产生影响。我在这个问题下贴了一个链接,链接到一篇详细讨论这个问题的文章。我认为不值得投反对票,但这是需要考虑的。@Larnu。这与索引的使用无关。索引中
CallTime
的目的是覆盖
WHERE
子句。可以直接查找前两列。我不认为直接查找会有太多的混乱。“最佳索引”实际上可能会根据参数以不同的顺序显示所有3个字段。这就是为什么最佳索引取决于实际发生的参数组合。我有类似的查询,在我的例子中,FromDate(很可能是DateTime)实际上是最有选择性的,因为很少有查询类型。在运行了几个不同版本的查询之后,它“神奇地”在<3秒内开始运行。这是典型的-它基本上被一个选择性索引(基于第一个参数集)卡住了,这对另一个参数集来说是完全不好的,但是,嘿,让我们重新使用一个查询计划。你说的“将查询标记为未知优化”是什么意思?@MattSpinks-新功能,基本上优化为一个稳定但并非真正超高效的计划。这不是一个好的通用解决方案,但值得一试。