需要为非常大的表重新分解/索引建议

时间:2015-03-15 15:38:44

标签: sql sql-server performance large-data

好的,所以我有一张桌子,只是变成了一个怪物。对我们的一些客户来说,查询它已经变得非常缓慢。这是相关表格:

    CREATE TABLE [EventTime](
    [Id] [bigint] IDENTITY(1,1) NOT NULL,
    [EventId] [bigint] NOT NULL,
    [Time] [datetime] NOT NULL,
    CONSTRAINT [PK_EventTime] PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    )
)
CREATE NONCLUSTERED INDEX [IX_EventTime_Main] ON [EventTime]
(
    [Time] ASC,
    [EventId] ASC
)

它有一个到事件表的FK。事件是从certian用户,ip,service和accountId采取的操作。此EventTime表告诉我们在什么时间发生了什么事件。今天凌晨3点和上周12点都会举办活动。我们的想法是不重复事件行。

现在,对于一些客户来说,这个EventTime表已经变得非常庞大;我们最大的是240万行并且在增长。在查看时间设置时,查询它变得极其缓慢>几天。这是我们今天正在执行的查询(注意:我在本地运行查询,以最大限度地减少网络延迟或收集者点击数据库导致的TO): / p>

SELECT 
a.TrailId, a.[NameId], a.[ResourceId], a.[AccountId], a.[ServiceId]
FROM [EventTime] b WITH (NOLOCK) INNER JOIN [Event] a WITH (NOLOCK) ON a.Id = b.EventId 
WHERE 
a.TrailId IN (1, 2, 3, 4, 5) AND 
a.NameId IN (6) AND 
b.[Time] >= '2014-10-29 00:00:00.000' AND 
b.[Time] <= '2014-11-12 23:59:59.000'  
ORDER BY b.[Time] ASC

注意,trailId是Event表中的一列,它告诉我们要在查询中过滤到哪个客户。在执行此查询之前,我们有TrailId列表。现在这个查询非常慢,大约需要45分钟才能执行。以下是我尝试的一些问题:

SELECT 
a.EventId, a.[NameId], a.[ResourceId], a.[AccountId], a.[ServiceId]
FROM [EventTime] b WITH(NOLOCK)
JOIN [Event] a WITH(NOLOCK) on a.Id = b.EventId
WHERE 
b.EventId IN (SELECT Id from [Event] where TrailId IN (1, 2, 3, 4, 5) AND NameId IN (6) ) AND 
b.[Time] >= '2014-08-01 00:00:00.000' AND 
b.[Time] <= '2014-11-12 23:59:59.000' AND
ORDER BY b.[Time] ASC

子查询适用于小型查询,但对于较大的日期范围,性能受到很大影响。接下来我试了

DECLARE @ListofIDs TABLE(Ids bigint)
INSERT INTO @ListofIDs (Ids)
SELECT Id from Event where TrailId IN (140, 629, 630, 631, 632) AND NameId IN (468) 


SELECT 
a.EventId, a.[NameId], a.[ResourceId], a.[AccountId], a.[ServiceId]
FROM [EventTime] b WITH(NOLOCK) 
JOIN [Event] a WITH(NOLOCK) on a.Id = b.EventId
WHERE 
b.EventId IN (SELECT Ids FROM @ListofIDs) AND 
b.[Time] >= '2014-08-01 00:00:00.000' AND 
b.[Time] <= '2014-11-12 23:59:59.000' AND
ORDER BY b.[Time] ASC

将我的子查询转换为表数组以供我的主要查询引用确实有所帮助。查询花了大约33分钟。但它仍然太慢= /

接下来我尝试使用索引。我想我可能过多地投入一个索引。所以我放弃了现有的并把它分成了两个。

CREATE NONCLUSTERED INDEX [IX_EventTime_Main] ON [EventTime]
(
    [Time] ASC,
)
GO
CREATE NONCLUSTERED INDEX [IX_EventTime_Event] ON [EventTime]
(
    [EventId] ASC
)

这似乎没有做任何事情。相同的查询时间。 我认为核心问题是,这个表格非常无组织。 “时间”列具有非常具体的时间值,并且它们都没有按顺序排列。例如,客户8的收集者可能正在为2014-11-12 04:12:01.000保存EventTimes,而客户10正在保存2015-03-15 13:59:21.000。因此,查询必须在过滤之前处理和排序所有这些日期。所以索引[时间]可能根本没有效果。

任何人对如何加快速度有任何想法?

2 个答案:

答案 0 :(得分:0)

这是您的查询:

SELECT e.TrailId, e.[NameId], e.[ResourceId], e.[AccountId], e.[ServiceId]
FROM [EventTime] et WITH (NOLOCK) INNER JOIN
     [Event] e WITH (NOLOCK)
     ON e.Id = et.EventId 
WHERE e.TrailId IN (1, 2, 3, 4, 5) AND 
      e.NameId = 6 AND 
      et.[Time] >= '2014-10-29 00:00:00.000' AND 
      et.[Time] <= '2014-11-12 23:59:59.000'  
ORDER BY et.[Time] ASC

此查询的最佳索引可能是:Event(NameId, TrailId)EventTime(EventId, Time)。这假设结果集不是很大(数千万行),在这种情况下,需要优化摆脱order by

答案 1 :(得分:0)

我会抛弃ID列并使主键成为EventId和Time上的复合聚类:

 CREATE TABLE [EventTime](
    [EventId] [bigint] NOT NULL,
    [Time] [datetime] NOT NULL,
    CONSTRAINT [PK_EventTime] PRIMARY KEY CLUSTERED 
    (
        [EventId] ASC
        , [Time] ASC
    )
)
CREATE NONCLUSTERED INDEX [IX_EventTime_Main] ON [EventTime]
(
    [Time] ASC,
    [EventId] ASC
);

检查执行计划以查看是否使用了非聚集索引并删除了不需要的索引。