【问题标题】:Need re-factoring / indexing advice for a very large table需要对非常大的表进行重构/索引建议
【发布时间】:2015-05-17 17:20:04
【问题描述】:

好的,所以我有一张刚刚变成怪物的桌子。对于我们的一些客户来说,查询它变得异常缓慢。这是有问题的表格:

    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。事件是从特定用户、ip、服务和 accountId 执行的操作。这个 EventTime 表告诉我们什么事件发生在什么时间。今天的凌晨 3 点和上周的中午 12 点都可能发生事件。这个想法是不重复事件行。

现在这个 EventTime 表对于一些客户来说已经变得很庞大了;我们最大的是 240mill 行并且还在增长。当查看时间设置>几天时,查询它变得异常缓慢。这是我们今天正在执行的查询(注意:我正在本地从数据库中运行查询,以最大限度地减少网络延迟或收集器访问数据库引起的 TO):

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 表中的一列,它告诉我们要在查询中过滤到哪些客户。在我们执行这个查询之前,我们有 TrailIds 的列表。现在这个查询很慢,执行大约需要 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
)

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

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

【问题讨论】:

  • 根据语法,我猜这是 SQL Server。
  • 正确。抱歉,忘记说明了。
  • 您是说事件不能有重复永远,或者它不能在特定时间段内重复。如果曾经,那么一位客户有 140 毫米的独特事件!?!哦,您可能会尝试摆脱 NOLOCK 提示。是的,我可以从这里听到“但是……”。试试看吧。

标签: sql sql-server performance large-data


【解决方案1】:

这是您的查询:

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

【讨论】:

    【解决方案2】:

    我会放弃 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
    );
    

    检查执行计划以查看是否使用了非聚集索引并将其删除。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-17
      • 1970-01-01
      • 2016-04-28
      • 1970-01-01
      • 1970-01-01
      • 2021-12-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多