SQL Server 索引/SQL 性能增强

标签 sql indexing sql-server-2008-r2 database-performance

我在 SQL Server 中有一个如下所示的表:

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 = True,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%的时间花在了排序上,也就是Partition/Order窗口函数。

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。

最佳答案

跟进评论:

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

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

  • 尝试替换标量值函数。

  • 检查色谱柱的选择性

    EquipID, EventTimeStamp, EventMilliSeconds, EventID, EventOn 
    

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

例如,EquipId 列的选择性将是

(SELECT COUNT(DISTINCT EquipId) FROM dbo.FCT_RawEvents) /
    (SELECT COUNT(*) FROM dbo.FCT_RawEvents)
  • 确保您的统计数据是最新的。

关于SQL Server 索引/SQL 性能增强,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14477536/

相关文章:

mysql - 如何在mysql中定义一个100亿行的key/value表?

SQL,左连接表,如何只保留一个值?

mysql - 如何从索引中获取枚举元素

sql - 如何在Sql服务器中将十六进制转换为字符串

sql - 总计值与 SSRS 中的前 N ​​个筛选值不匹配

sql - Delphi与SQL Server之间的冲突

php - SQL 字符串替换为 ID 语句

mysql - 如何在 SQL 内连接中添加别名?

indexing - 暂时阻止Google搜寻器,是否会阻止以后编制索引?

MYSQL: LEFT() 不使用任何索引