【问题标题】:Optimize table to read the most recent rows优化表以读取最近的行
【发布时间】:2017-06-28 08:47:28
【问题描述】:

我有两个表,我们每天添加大约 100k 和 150 万个新行。这些是日志条目,在超过 99% 的情况下,我对阅读时的最后 3 个工作日感兴趣。

如果我运行一个简单的查询,例如

SELECT
0 as Id, ProcessElementName, Null as ModelPath, Status, Remark, ValidFrom, Application, JobID, JobName, CreateDate, CreatedBy, MessageType, Running, Manual, Environment, RunIdentifier, BatchJobGroup, BatchJob, IsTemp, TotalRows = COUNT(*) OVER() 
FROM dbo.pclTB_ProcessElementInfo WITH (NOLOCK)
WHERE
ValidFrom > '6/26/2017 12:00:00 AM'
AND ValidFrom <= '6/26/2017 11:59:59 PM'
AND (Environment in ('---')) AND
(
Remark LIKE '%' + 'btve' + '%'
AND Application = '---'
AND (IsTemp = 0 OR IsTemp IS NULL )
AND ProcessElementName = '---'
)
ORDER BY JobID ASC
OFFSET 0 ROWS FETCH NEXT 1000 ROWS ONLY

最多可能需要 10 秒。其他查询中有一些连接,但大多数都很简单。 当我手动更新统计信息时,执行时间下降到大约 2 秒,但我确信仍有改进的空间(我知道跟踪标志 2371)。

优化表(或查询?)以获取最新行的最佳方法是什么?仅使用最近 X 天的条目创建一个新表是否有意义?

编辑: 这是用于上述查询的索引

CREATE NONCLUSTERED INDEX [IX_ProcessElementNameApplicationEnvironmentValidFrom] ON [dbo].[pclTB_ProcessElementInfo]
(
    [ProcessElementName] ASC,
    [Application] ASC,
    [Environment] ASC,
    [ValidFrom] ASC
)
INCLUDE (
    [Status],
    [Remark],
    [JobID],
    [JobName],
    [CreateDate],
    [CreatedBy],
    [MessageType],
    [Running],
    [Manual],
    [RunIdentifier],
    [BatchJobGroup],
    [BatchJob],
    [IsTemp]
    )
    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]

【问题讨论】:

  • 您正在寻找的是分区。
  • @swift 你能告诉我们你的索引是什么样的吗?我的观点是,它们教会我们使索引尽可能具有选择性,这意味着通常索引以时间戳开头,这对于此类查询来说是最糟糕的选择。
  • Remark LIKE '%' + 'btve' + '%'AND (IsTemp = 0 OR IsTemp IS NULL ) 是杀手。我建议将您的表结构更改为将 IsTemp 作为不可为空的列,并将 NULL 替换为 0。然后您可以使用 IsTemp = 0 条件创建过滤索引。
  • 我会将isTemp 作为索引的第一列。正如 Evaldas 所说的,这里的杀手可能是用它来评论的。也许将此列也放入索引中,而不是将其放入包含的列中。我在这里看不到任何其他机会。
  • 关于备注栏,我不确定是在 ValidFrom 之前还是之后更好。所以你可能需要尝试一下。

标签: sql sql-server query-optimization sql-optimization


【解决方案1】:

当您将数据插入到表中时,插入到保存最近 x 天记录的另一个表中。然后您可以使用存储过程在一定时间后自动删除记录。 How to automatically delete records in sql server after a certain amount of time

【讨论】:

    【解决方案2】:

    您可以考虑使用表partitioning。假设您将为过去 3 天和其余数据创建分区。然后,您将更新您的查询以仅使用该特定分区。
    它有一些限制,例如您只能按用于聚集索引的数据进行分区,但这可能是一种方式。
    您不一定必须使用上面链接中提到的不同文件组。这是另一个可能会让您感到不安的链接。关于How to Implement an Automatic Sliding Window in a Partitioned Table on SQL Server 2005

    【讨论】:

    • @Swit 必须确认他们是否有企业版。
    • 我们有两个开发版数据库和一个企业版数据库。需要明确的是,分区必须是静态的,我们不能使用相对日期,对吧?
    • 分区仅适用于企业版。
    【解决方案3】:

    您可能需要每天重新创建过滤索引。您现有的索引可以与过去三天的日期过滤重复:

    DECLARE @sql varchar(8000) = '
    
    IF EXISTS (SELECT 1 FROM sys.indexes WHERE name = ''IX_IndexName'')
        DROP INDEX IX_IndexNameON My_table ;
    
    CREATE NONCLUSTERED INDEX IX_IndexNameON My_table (
        timestamp 
    )
    WHERE timestamp > ''' + CONVERT(varchar(25),DATEADD(d,-3,GETDATE()) ,121) + ''';';
    
    EXEC (@sql);
    

    【讨论】:

      猜你喜欢
      • 2014-01-11
      • 2012-07-11
      • 1970-01-01
      • 1970-01-01
      • 2018-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-23
      相关资源
      最近更新 更多