【问题标题】:SQL Server : MERGE performanceSQL Server:合并性能
【发布时间】:2013-08-11 04:47:06
【问题描述】:

我有一个包含 500 万行的数据库表。聚集索引是自增标识列。 PK是生成256字节VARCHAR的代码,这是一个URL的SHA256哈希,这是表上的一个非聚集索引。

表格如下:

CREATE TABLE [dbo].[store_image](
    [imageSHAID] [nvarchar](256) NOT NULL,
    [imageGUID] [uniqueidentifier] NOT NULL,
    [imageURL] [nvarchar](2000) NOT NULL,
    [showCount] [bigint] NOT NULL,
    [imageURLIndex]  AS (CONVERT([nvarchar](450),[imageURL],(0))),
    [autoIncID] [bigint] IDENTITY(1,1) NOT NULL,
 CONSTRAINT [PK_imageSHAID] PRIMARY KEY NONCLUSTERED 
(
    [imageSHAID] 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

CREATE CLUSTERED INDEX [autoIncPK] ON [dbo].[store_image] 
(
    [autoIncID] 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
  • imageSHAID 是图像 URL 的 SHA256 哈希,例如“http://blah.com/image1.jpg”,哈希成256长度的varchar。

  • imageGUID 是代码生成的 guid,我在其中识别图像(稍后将用作索引,但现在我省略了此列作为索引)

  • imageURL 是图片的完整 URL(最多 2000 个字符)

  • showCount 是图像显示的次数,每次显示此特定图像时都会递增。

  • imageURLIndex 是一个限制为 450 个字符的计算列,这使我可以在我选择的 imageURL 上进行文本搜索,它是可索引的(再次为简洁省略索引)

    李>
  • autoIncID 是聚集索引,应该允许更快地插入数据。

我会定期从临时表合并到 store_image 表中。 temp表结构如下(与store_image表非常相似):

CREATE TABLE [dbo].[store_image_temp](
    [imageSHAID] [nvarchar](256) NULL,
    [imageURL] [nvarchar](2000) NULL,
    [showCount] [bigint] NULL,
) ON [PRIMARY]

GO

运行合并过程时,我使用以下代码将DataTable 写入临时表:

using (SqlBulkCopy bulk = new SqlBulkCopy(storeConn, SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.KeepNulls, null))
{
    bulk.DestinationTableName = "[dbo].[store_image_temp]";
    bulk.WriteToServer(imageTableUpsetDataTable);
}

然后我运行合并命令来更新store_image 表中的showCount,方法是从基于imageSHAID 的临时表中进行合并。如果图像当前不存在于 store_image 表中,我创建它:

merge into store_image as Target using [dbo].[store_image_temp] as Source
on Target.imageSHAID=Source.imageSHAID 
when matched then update set 
Target.showCount=Target.showCount+Source.showCount 
when not matched then insert values (Source.imageSHAID,NEWID(), Source.imageURL, Source.showCount);

我通常会尝试在任何一个合并过程中将临时表中的 2k-5k 行合并到 store_image 表中。

我曾经在 SSD(仅连接 SATA 1)上运行此数据库,而且速度非常快(不到 200 毫秒)。我的 SSD 空间不足,所以我将 DB 换成了 1TB 7200 高速缓存旋转磁盘,此后完成时间超过 6-100 秒(6000 - 100000MS)。当批量插入运行时,我可以看到大约 1MB-2MB/秒的磁盘活动,CPU 使用率很低。

对于这种数据量,这是典型的写入时间吗?对我来说似乎有点慢,是什么导致性能缓慢?当然,随着imageSHAID 被编入索引,我们应该期望比这更快的查找时间?

任何帮助将不胜感激。

感谢您的宝贵时间。

【问题讨论】:

    标签: sql sql-server merge sqlperformance


    【解决方案1】:

    MERGE 中的 UPDATE 子句会更新 showCount。这需要对聚集索引进行键查找。

    但是,聚集索引也被声明为非唯一的。即使底层列是唯一的,这也会为优化器提供信息。

    所以,我会做出这些改变

    • 集群主键为autoIncID
    • imageSHAID 上的当前 PK 作为独立的唯一索引(非约束)并为 showCount 添加一个 INCLUDE。唯一约束不能包含 INCLUDE

    更多观察:

    【讨论】:

    • 你好,这似乎有很大的改善,我进行了一些测试,合并时间似乎更低:3.7k @ 24 秒 2.6k @ 2.4 秒 2.8k @ 11 秒 1.3k @ 1.1 秒2.6k @ 2.5 秒 2.1k @ 2.6 秒,这些合并时间是否合适?纠正“其他观察”会进一步改善吗?我认为 2-3k 行合并总是需要不到 500 毫秒。
    • 其他观察将减少磁盘和内存的使用,更少的字节转移(例如事务日志)。并帮助优化器高效分配内存。
    • 即使在您建议的更改之后,我的性能仍然很差。我有一些持续 70 秒以上的合并。鉴于我已经对索引/PK 进行了更改,您能否解释一下我调用合并时发生了什么,肯定它是在 imageSHAID 独立唯一索引上使用索引查找,这应该很快吗?
    • autoIncID 上的集群索引确实有助于提高性能。接受作为答案。
    猜你喜欢
    • 2011-11-29
    • 2020-04-16
    • 2018-12-24
    • 2014-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多