2013-01-23 86 views
3

我在SQL Server中的表看起来像这样:的SQL Server索引/ SQL性能增强

CREATE TABLE [dbo].[FCT_RawEvents](
    [EquipID] [int] NOT NULL, 
    [EventTimeStamp] [int] NOT NULL, 
    [EventMilliSeconds] [smallint] NULL, 
    [EventID] [int] NOT NULL, 
    [EventOn] [bit] NOT NULL, 
    [JobID] [int] NULL, 
    [FirstEvent] [bit] NULL, 
    [OperatorId] [int] NULL, 
    [Suppressed] [bit] NULL, 
    [ManualOverride] [bit] NULL 
) 

这包含事件,即要么打开或关闭(EventOn =真,EventOn = FALSE)。现在我需要在给定的时间获得所有'活动'(未被抑制)的事件。我有一些SQL可以工作,但是由于这个表的行数在几百万,所以它运行速度很慢(5个equipIds需要10秒)。

这就是:

DECLARE @StartDateTime datetime = '2013/01/01' 
DECLARE @csvEquipIds nvarchar(MAX) = '5,6,7,8' 

DECLARE @StartTimeStamp int = dbo.GetSecondsFromDate(@StartDateTime) 
DECLARE @StartMilliSeconds smallint = DATEPART(Ms, @StartDateTime) 

DECLARE @EquipIds TABLE (EquipId int) 
INSERT INTO @EquipIds(EquipId) SELECT EquipID FROM dbo.getEquipmentIDs(null,@csvEquipIds) 

SELECT dbo.getDateFromSeconds(EventTimeStamp), * FROM 
    ( SELECT re.EquipID,EventTimeStamp,EventMilliSeconds,EventID,eventon, 
      ROW_NUMBER() OVER (PARTITION BY re.EquipId,EventID ORDER BY EventTimeStamp DESC,EventMilliSeconds DESC) AS RowNo 
     FROM dbo.FCT_RawEvents re 
     JOIN @EquipIds eq 
     ON eq.EquipId = re.EquipID 
     WHERE (re.EventTimeStamp < @StartTimeStamp OR(re.EventTimeStamp = @StartTimeStamp AND re.EventMilliSeconds <= @StartMilliSeconds)) AND re.EventID > 0 
     AND (re.Suppressed IS NULL)-- OR re.Suppressed = 0) 
    ) ev 
WHERE RowNo = 1 AND EventOn = 1 

ORDER BY EquipID,EventID, EventTimeStamp desc, EventMilliSeconds desc 

执行计划表明,80%的时间花费在排序,这是分区/订单窗口的功能。

Execution Plan:

我绝不是INDEX专家,但已经添加了这些:

CREATE CLUSTERED INDEX [IX_Clustered] ON [dbo].[FCT_RawEvents] 
(
    [EquipID] ASC, 
    [EventTimeStamp] DESC, 
    [EventMilliSeconds] DESC, 
    [EventID] ASC, 
    [EventOn] DESC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
GO 

CREATE NONCLUSTERED INDEX [IX_EquipEventTime] ON [dbo].[FCT_RawEvents] 
(
    [EquipID] ASC, 
    [EventID] ASC, 
    [EventTimeStamp] DESC, 
    [EventMilliSeconds] DESC 
) 
INCLUDE ([EventOn]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
GO 

CREATE NONCLUSTERED INDEX [IX_Suppressed] ON [dbo].[FCT_RawEvents] 
(
    [Suppressed] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
GO 

看来,那种被扫描表,在这里我真的希望它的很大一部分'回顾'直到找到第一个匹配的事件。

任何指针将不胜感激,无论是通过使用索引或改进SQL。

+0

我猜你在桌子上有一些索引。你也可以添加它们吗?我在屏幕截图上看到两个“Table Scan”,看起来这个黄色长方形隐藏了某种“seek”。避免表扫描。 [这个链接]也许可以提供帮助。 – Yaroslav

+3

你的第二个索引看起来很大程度上是多余的(取决于你的查询工作量当然) –

+2

尝试使用临时表而不是表变量;你也可以摆脱缩放的UDF,getDateFromSeconds? –

回答

1

跟进评论:

  • 尝试用临时表替换表变量:表变量也没有统计,临时表可以。

  • 第二个索引看起来是多余的。

  • 尝试替换标量值函数。

  • 检查你列

    EquipID, EventTimeStamp, EventMilliSeconds, EventID, EventOn 
    

的选择性和高选择性的顺序创建索引到最低。选择性是一列中有多少重复值的度量。它的范围从无重复(高选择性)到所有相同的值(零选择性)。理想情况下,索引应具有最高选择性顺序的列。

例如,您EquipId列的选择性会

(SELECT COUNT(DISTINCT EquipId) FROM dbo.FCT_RawEvents)/
    (SELECT COUNT(*) FROM dbo.FCT_RawEvents) 
  • 确保您的统计信息是最新的。
+0

感谢米奇。 “选择性”是什么意思? –