4

我有一个包含 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使用以下代码将 a 写入临时表:

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

然后我运行合并命令,showCount通过store_image从基于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);

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

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

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

任何帮助,将不胜感激。

谢谢你的时间。

4

1 回答 1

6

您在更新UPDATE中的子句。这需要对聚集索引进行键查找。MERGEshowCount

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

所以,我会做出这些改变

  • 聚集的主键是autoIncID
  • 当前 PKimageSHAID成为独立的唯一索引(不是约束)并为showCount. 唯一约束不能包含 INCLUDE

更多观察:

  • 您不需要nvarchar哈希或 URL 列。这些不是 unicode。
  • 哈希也是固定长度char(64)的(对于 SHA2-512)。
  • 列的长度定义了分配给查询的内存量。查看更多信息:varchar(500) 是否比 varchar(8000) 有优势?
于 2013-08-09T09:40:13.933 回答