Depuis la rédaction de l' article d'Itzik Ben Gan, la taille de la mémoire cache codée en dur de 10 IDENTITY
semble avoir été modifiée. Parmi les commentaires sur cet élément de connexion
La taille de la pré-allocation est basée sur la taille du type de données de la colonne sur laquelle la propriété d'identité est définie. Pour une colonne entière SQL Server, le serveur préalloue des identités dans des plages de 1 000 valeurs. Pour le type de données bigint, le serveur effectue une pré-affectation dans des plages de 10 000 valeurs.
Le manuel d' interrogation T-SQL contient le tableau suivant, mais souligne que ces valeurs ne sont ni documentées ni garanties d'être inchangées.
+-----------------+-----------+
| DataType | CacheSize |
+-----------------+-----------+
| TinyInt | 10 |
| SmallInt | 100 |
| Int | 1,000 |
| BigInt, Numeric | 10,000 |
+-----------------+-----------+
L'article ici teste différentes tailles de cache de séquence et de tailles de lot d'insertion et donne les résultats suivants.
Ce qui semble montrer que pour les grands inserts IDENTITY
out effectue SEQUENCE
. Cependant, il ne teste pas la taille de cache 1 000 et ces résultats ne sont qu'un test. En examinant spécifiquement la taille du cache 1 000 avec différentes tailles de lots d'insertions, j'ai obtenu les résultats suivants (essayer 50 fois la taille de chaque lot et agréger les résultats comme ci-dessous - tous les temps sont en μs.)
+------------+-----------+-----------+-----------+-----------+-----------+-----------+
| | Sequence | Identity |
| Batch Size | Min | Max | Avg | Min | Max | Avg |
+------------+-----------+-----------+-----------+-----------+-----------+-----------+
| 10 | 2,994 | 7,004 | 4,002 | 3,001 | 7,005 | 4,022 |
| 100 | 3,997 | 5,005 | 4,218 | 4,001 | 5,010 | 4,238 |
| 1,000 | 6,001 | 19,013 | 7,221 | 5,982 | 8,006 | 6,709 |
| 10,000 | 26,999 | 33,022 | 28,645 | 24,015 | 34,022 | 26,114 |
| 100,000 | 189,126 | 293,340 | 205,968 | 165,109 | 234,156 | 173,391 |
| 1,000,000 | 2,208,952 | 2,344,689 | 2,269,297 | 2,058,377 | 2,191,465 | 2,098,552 |
+------------+-----------+-----------+-----------+-----------+-----------+-----------+
Pour les lots de plus grande taille, la IDENTITY
version semble généralement plus rapide .
Le manuel TSQL Querying explique également pourquoi IDENTITY
un avantage en termes de performances est obtenu par rapport à la séquence.
La IDENTITY
table est spécifique et SEQUENCE
ne l'est pas. Si un sinistre devait frapper mi insertion avant que le tampon de journal ne soit vidé, peu importe si l'identité récupérée est antérieure, le processus de récupération annulant également l'insertion, de sorte que SQL Server ne force pas le vidage du tampon de journal pour chaque identité. cache lié disque écrire. Cependant, pour Sequence, ceci est appliqué car la valeur peut être utilisée à n'importe quelle fin, y compris en dehors de la base de données. Ainsi, dans l'exemple ci-dessus, avec un million d'insertions et une taille de cache de 1 000, il s'agit de mille vidages supplémentaires du journal.
Script à reproduire
DECLARE @Results TABLE(
BatchCounter INT,
NumRows INT,
SequenceTime BIGINT,
IdTime BIGINT);
DECLARE @NumRows INT = 10,
@BatchCounter INT;
WHILE @NumRows <= 1000000
BEGIN
SET @BatchCounter = 0;
WHILE @BatchCounter <= 50
BEGIN
--Do inserts using Sequence
DECLARE @SequenceTimeStart DATETIME2(7) = SYSUTCDATETIME();
INSERT INTO dbo.t1_Seq1_cache_1000
(c1)
SELECT N
FROM [dbo].[TallyTable] (@NumRows)
OPTION (RECOMPILE);
DECLARE @SequenceTimeEnd DATETIME2(7) = SYSUTCDATETIME();
--Do inserts using IDENTITY
DECLARE @IdTimeStart DATETIME2(7) = SYSUTCDATETIME();
INSERT INTO dbo.t1_identity
(c1)
SELECT N
FROM [dbo].[TallyTable] (@NumRows)
OPTION (RECOMPILE);
DECLARE @IdTimeEnd DATETIME2(7) = SYSUTCDATETIME();
INSERT INTO @Results
SELECT @BatchCounter,
@NumRows,
DATEDIFF(MICROSECOND, @SequenceTimeStart, @SequenceTimeEnd) AS SequenceTime,
DATEDIFF(MICROSECOND, @IdTimeStart, @IdTimeEnd) AS IdTime;
TRUNCATE TABLE dbo.t1_identity;
TRUNCATE TABLE dbo.t1_Seq1_cache_1000;
SET @BatchCounter +=1;
END
SET @NumRows *= 10;
END
SELECT NumRows,
MIN(SequenceTime) AS MinSequenceTime,
MAX(SequenceTime) AS MaxSequenceTime,
AVG(SequenceTime) AS AvgSequenceTime,
MIN(IdTime) AS MinIdentityTime,
MAX(IdTime) AS MaxIdentityTime,
AVG(IdTime) AS AvgIdentityTime
FROM @Results
GROUP BY NumRows;