【问题标题】:Increasing performance on a logging table in SQL Server 2005在 SQL Server 2005 中提高日志记录表的性能
【发布时间】:2010-12-05 12:19:23
【问题描述】:

我有一个“历史”表,我将每个请求记录到我们网站上的 Web 处理程序中。这是表定义:

/****** Object:  Table [dbo].[HistoryRequest]    Script Date: 10/09/2009 17:18:02 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[HistoryRequest](
    [HistoryRequestID] [uniqueidentifier] NOT NULL,
    [CampaignID] [int] NOT NULL,
    [UrlReferrer] [nvarchar](512) NOT NULL,
    [UserAgent] [nvarchar](512) NOT NULL,
    [UserHostAddress] [nvarchar](15) NOT NULL,
    [UserHostName] [nvarchar](512) NOT NULL,
    [HttpBrowserCapabilities] [xml] NOT NULL,
    [Created] [datetime] NOT NULL,
    [CreatedBy] [nvarchar](100) NOT NULL,
    [Updated] [datetime] NULL,
    [UpdatedBy] [nvarchar](100) NULL,
 CONSTRAINT [PK_HistoryRequest] PRIMARY KEY CLUSTERED 
(
    [HistoryRequestID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[HistoryRequest]  WITH CHECK ADD  CONSTRAINT [FK_HistoryRequest_Campaign] FOREIGN KEY([CampaignID])
REFERENCES [dbo].[Campaign] ([CampaignId])
GO

ALTER TABLE [dbo].[HistoryRequest] CHECK CONSTRAINT [FK_HistoryRequest_Campaign]
GO

此语句的 1050 行需要 37 秒:

SELECT * 
  FROM HistoryRequest AS hr 
 WHERE Created > '10/9/2009'
 ORDER BY Created DESC

有没有人有任何加快这个速度的建议?我在 PK 上有一个聚集索引,在 CREATED 列上有一个常规索引。我尝试了唯一索引,但它抱怨某处有重复条目 - 这是可以预料的。

欢迎任何见解!

【问题讨论】:

    标签: sql sql-server sql-server-2005 tsql performance


    【解决方案1】:

    您正在请求非覆盖索引(已创建)上的所有列 (*)。在大型数据集上,您可以保证访问Index Tipping Point,在该处,聚集索引扫描比非聚集索引范围查找和书签查找更有效。

    你总是需要 * 吗?如果是,并且如果典型的访问模式是这样的,那么您必须相应地组织表并使 Created 成为最左边的聚集键。

    如果不是,请考虑将您的查询更改为可覆盖的查询,例如。仅选择非聚集索引覆盖的 HistoryRequestID 和 Created。如果需要更多字段,请将它们作为包含列添加到非聚集索引中,但要考虑到这会增加额外的存储空间和 IO 日志写入时间。

    【讨论】:

    • 对不起 - SELECT * 只是 SQL Mangler 中的一个折腾。我不是这样写我的实际代码的。我试图找出一个问题,并用“SELECT *”挖掘数据。我还对这个确切的语句做了一个查询计划,尽管 100% 进入了索引扫描,但没有显示表扫描。
    • 是聚集索引扫描还是非聚集索引扫描?聚集索引扫描与“表扫描”相同,因为聚集索引表。
    【解决方案2】:

    嘿,我在大集合中提取 XML 列时看到了一些奇怪的行为。尝试将索引放在 Created back 上,然后在 select 语句中指定列;但省略 XML。看看这如何影响结果的返回时间。

    【讨论】:

    • 我会玩这个。谢谢!
    • 我将 XML 列拉出并放入一个新创建的表 (HistoryRequestExtended) 中。这一动作释放了我的陈述,它又回到了快速尖叫的状态。 (即使使用 SELECT * 也是“错误的”)。谢谢! :)
    • 嘿,没问题...像这样的东西就是为什么我们停止在我的 SQL 2005 数据库中使用 XML 数据类型的原因。相反,我们倾向于将数据存储在 ntext 中,并在代码中完成所有 XML 工作。我们计划在几个月后确定 SQL 2008 是否对此有所改进。
    【解决方案3】:

    对于日志表,您可能不需要 uniqueidentifier 列。您也不太可能查询它,因此它不是聚集索引的好候选者。您的示例查询在“已创建”上,但上面没有索引。如果您经常查询“已创建”值的范围,那么即使它不一定是唯一的,它也将是一个很好的聚类候选对象。

    OTOH,外键建议 Campaign 进行频繁查询,在这种情况下,由该列完成集群可能是有意义的,并且还可能会更好地分散索引中的插入键 - 代理键和时间戳会按顺序添加记录,随着时间的推移,插入的净工作量会增加,因为节点扇区的随机填充较少。

    如果它只是一个日志表,为什么它有更新审计列?它通常是只写的。

    【讨论】:

      【解决方案4】:

      重建索引。在适当的情况下在表名之后使用 WITH (NOLOCK) 子句,如果您想对实时环境中大量使用的表(例如日志文件)运行长时间(ish)运行查询,这可能适用。这基本上意味着您的查询可能会错过一些最新的记录,但您也没有在表上保持打开锁 - 这会产生额外的开销。

      【讨论】:

      • 如果要更频繁地使用,还可以考虑将集群放在日期列上。
      猜你喜欢
      • 2011-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-14
      • 1970-01-01
      相关资源
      最近更新 更多