Чому послідовності Denali повинні працювати краще, ніж стовпці ідентичності?


36

У своїй відповіді на те, що краще: стовпці ідентифіковані або генеровані унікальні значення ідентифікатора? mrdenny каже:

Коли SQL Denali вийде, він буде підтримувати послідовності, які будуть більш ефективними, ніж ідентичність, але ви не можете створити щось більш ефективне самостійно.

Я не такий впевнений. Знаючи послідовності Oracle , я повинен створити тригер для вставки, інкапсулювати кожну вставку у виклик збереженої процедури, або молитись, щоб я не забував правильно використовувати послідовність, коли я роблю спеціальну вставку.

Сумніваюся, що переваги послідовностей такі очевидні.


2
Я знаю, що це не відповідає на ваше запитання, але окрім будь-якої різниці в продуктивності, послідовності мають інші переваги. Наприклад, послідовність не зупиняє вас оновлення цільового стовпця, що є дуже незручним обмеженням IDENTITY.
nvogel

Відповіді:


37

Я відповім і тут. Це пов'язано з внутрішніми принципами роботи IDENTITYта SEQUENCEроботи.

З IDENTITY, SQL Server попередньо кешує значення в пам'ять, щоб вони були легко доступними. Детальну інформацію див. У відповіді Мартіна Сміта . У міру використання значень фоновий процес генерує більше значень. Як ви можете уявити, цей пул може закінчитися досить швидко, залишаючи програму на милість фонового процесу, який генерує значення.

З SEQUENCE, SQL Server дозволяє визначити, наскільки великим повинен бути кеш. Хоча SQL Server насправді не зберігає значення в кеші, він зберігає лише поточне значення та значення верхнього кінця, це значно зменшить кількість вводу-виводу, необхідного для створення значень.

Не встановлюйте кеш занадто високим, оскільки це зменшить кількість чисел, які можна використати: якщо SQL Server повинен вийти з ладу, будь-які значення, визначені в поточному діапазоні кешу, який не використовувався, втрачаються.

Що стосується вставки рядків, просто вкажіть значення стовпця за замовчуванням, наприклад:

DEFAULT (NEXT VALUE FOR Audit.EventCounter),

21

Оскільки стаття Іціка Бен Гана була написана, кешований кеш розміром 10 для, IDENTITYздається, був змінений. З коментарів до цього елемента підключення

Розмір попереднього розподілу заснований на розмірі типу даних стовпця, на який визначено властивість ідентичності. Для цілого стовпця SQL Server сервер попередньо виділяє ідентичності в діапазоні 1000 значень. Для типу даних bigint сервер попередньо виділяє в діапазоні 10000 значень.

The T-SQL Запити книга містить наступну таблицю , але підкреслює , що ці значення не документуються або гарантовано незмінними.

+-----------------+-----------+
|    DataType     | CacheSize |
+-----------------+-----------+
| TinyInt         | 10        |
| SmallInt        | 100       |
| Int             | 1,000     |
| BigInt, Numeric | 10,000    |
+-----------------+-----------+

Стаття тут перевіряє різні розміри кешу послідовностей та вставляє розміри партії та пропонує наступні результати.

введіть тут опис зображення

Яка видно, що показує, що для великих вставок IDENTITY виконує SEQUENCE. Однак він не перевіряє кеш-розмір 1000, але також ці результати є лише одним тестом. Дивлячись конкретно на кеш-розмір 1000 з різними розмірами партій вставок, я отримав такі результати (спробувавши кожний розмір партії в 50 разів та агрегувавши результати як нижче - всі часи в мкс).

+------------+-----------+-----------+-----------+-----------+-----------+-----------+
|            |             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 |
+------------+-----------+-----------+-----------+-----------+-----------+-----------+

Для великих розмірів партії IDENTITY версія здається, як правило, швидшою .

Книга запитів TSQL також пояснює, чому IDENTITYможе мати перевагу продуктивності перед послідовністю.

IDENTITYСтолове специфічні і SEQUENCEне є. Якщо катастрофа повинна була нанести середню вставку перед змивом буфера журналу, не має значення, якщо відновлений ідентифікатор є більш раннім, оскільки процес відновлення також скасує вставку, тому SQL Server не змушує перемикати буфер журналу на кожен ідентифікатор кеш-запис, пов'язаний із записом диска. Однак для Послідовності це буде виконано , оскільки значення може бути використано для будь-яких цілей - в тому числі і за межами бази даних. Отже, у наведеному вище прикладі з мільйоном вставок і розміром кешу в 1000 це додаткові тисячі журналів.

Сценарій для відтворення

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;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.