SQL Server: performances MERGE

J'ai une table de database avec 5 millions de lignes. L'index clusterisé est une colonne d'identité auto-incrémentée. PK est un code généré 256 octets VARCHAR qui est un hachage SHA256 d'une URL, c'est un index non-clustered sur la table.

Le tableau est le suivant:

 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 

Périodiquement, je fusionne à partir d'une table temporaire dans la table store_image . La structure de la table temporaire est la suivante (très similaire à la table store_image):

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

Lorsque le process de fusion est exécuté, j'écris un DataTable à la table temporaire en utilisant le code suivant:

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

Je lance ensuite la command merge pour mettre à jour le showCount dans la table store_image en fusionnant à partir de la table temporaire basée sur imageSHAID . Si l'image n'existe pas dans la table store_image , je la crée:

 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); 

J'essaie généralement de merge des lignes 2k à 5k de la table temporaire à la table store_image lors d'un process de fusion.

J'avais l'habitude de courir cette DB sur un SSD (seulement SATA 1 connecté) et c'était très rapide (less de 200 ms). J'ai manqué de place sur le disque SSD, j'ai donc changé la database en un disque tournant de 1 To 7200, car les time de réalisation sont alors de 6 à 100 secondes (6000 – 100000 ms). Lorsque l'insertion en bloc est en cours d'exécution, je peux voir l'activité du disque d'environ 1 Mo-2 Mo / s, faible utilisation du processeur.

Est-ce un time d'écriture typique pour cette quantité de données? Cela me semble un peu lent, qu'est-ce qui cause la lenteur de la performance? Sûrement avec l' imageSHAID étant indexé nous devrions nous attendre à des time de search plus rapides que ceci?

Toute aide serait appréciée.

Merci pour votre time.

Votre clause UPDATE dans MERGE met à jour showCount . Cela nécessite une search de key sur l'index clusterisé.

Cependant, l'index clusterisé est également déclaré non unique. Cela donne des informations à l'optimiseur même si la colonne sous-jacente est unique.

Donc, je ferais ces changements

  • la key primaire en cluster à autoIncID
  • PK actuel sur imageSHAID pour être un index unique autonome (pas de contrainte) et append un INCLUDE pour showCount . Les contraintes uniques ne peuvent pas avoir INCLUDE

Plus d'observations:

  • vous n'avez pas besoin de nvarchar pour les colonnes de hachage ou d'URL. Ce ne sont pas unicode.
  • Un hachage est également fixe longueur peut donc être char(64) (pour SHA2-512).
  • La longueur d'une colonne définit la quantité de memory à affecter à la requête. Voir ceci pour plus: Y at-il un avantage à varchar (500) sur varchar (8000)?