Tại sao các chuỗi Denali được cho là thực hiện tốt hơn các cột danh tính?


36

Trong câu trả lời của ông về cái nào tốt hơn: cột nhận dạng hoặc tạo các giá trị id duy nhất? mrdenny nói:

Khi SQL Denali xuất hiện, nó sẽ hỗ trợ các chuỗi sẽ hiệu quả hơn danh tính, nhưng bạn không thể tự tạo ra thứ gì đó hiệu quả hơn.

Tôi không chắc lắm. Biết các trình tự của Oracle , tôi phải tạo một trình kích hoạt để chèn, gói gọn mỗi lần chèn vào một lệnh gọi của thủ tục được lưu trữ hoặc cầu nguyện rằng tôi không quên sử dụng đúng trình tự khi tôi thực hiện thao tác chèn quảng cáo.

Tôi nghi ngờ rằng những lợi thế của trình tự là quá rõ ràng.


2
Tôi biết nó không trả lời câu hỏi của bạn nhưng ngoài bất kỳ sự khác biệt về hiệu suất, trình tự có những lợi thế khác. Ví dụ, một chuỗi không ngăn bạn cập nhật cột mục tiêu, đây là một hạn chế rất bất tiện của IDENTITY.
nvogel

Câu trả lời:


37

Tôi cũng sẽ trả lời ở đây. Nó phải làm với nội bộ về cách thức IDENTITYSEQUENCEcông việc.

Với IDENTITY, SQL Server lưu trữ trước các giá trị vào bộ nhớ để chúng có sẵn. Xem câu trả lời của Martin Smith để biết chi tiết. Khi các giá trị được sử dụng, một quá trình nền tạo ra nhiều giá trị hơn. Như bạn có thể tưởng tượng, nhóm này có thể hết khá nhanh, khiến ứng dụng bị ảnh hưởng bởi quá trình nền đang tạo ra các giá trị.

Với SEQUENCE, SQL Server cho phép bạn xác định mức độ lớn của bộ đệm. Mặc dù SQL Server không thực sự giữ các giá trị trong bộ đệm, nhưng nó chỉ giữ giá trị hiện tại và giá trị cuối cùng, điều này sẽ giúp giảm đáng kể lượng IO cần thiết để tạo giá trị.

Đừng đặt bộ đệm quá cao, vì điều này sẽ làm giảm số lượng số có thể được sử dụng: nếu SQL Server bị sập, mọi giá trị được chỉ định trong phạm vi bộ đệm hiện tại không được sử dụng sẽ bị mất.

Đối với chèn hàng, chỉ cần chỉ định một giá trị mặc định cho cột, như vậy:

DEFAULT (NEXT VALUE FOR Audit.EventCounter),

21

Kể từ khi bài viết Itzik Ben Gan được viết, kích thước bộ đệm được mã hóa là 10 cho IDENTITYdường như đã được thay đổi. Từ các ý kiến ​​về mục kết nối này

Kích thước của phân bổ trước dựa trên kích thước của kiểu dữ liệu của cột mà thuộc tính nhận dạng được xác định. Đối với cột số nguyên Máy chủ SQL, máy chủ phân bổ trước danh tính trong phạm vi 1000 giá trị. Đối với kiểu dữ liệu bigint, máy chủ phân bổ trước trong phạm vi 10000 giá trị.

Các T-SQL Truy vấn cuốn sách chứa bảng sau nhưng nhấn mạnh rằng những giá trị này không được ghi nhận hoặc bảo đảm là không thay đổi.

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

Bài viết ở đây kiểm tra các kích thước bộ đệm trình tự khác nhau và chèn kích thước lô và đưa ra các kết quả sau.

nhập mô tả hình ảnh ở đây

Điều này dường như cho thấy rằng đối với các chèn lớn IDENTITY thực hiện SEQUENCE. Tuy nhiên, nó không kiểm tra kích thước bộ đệm 1.000 và những kết quả đó chỉ là một thử nghiệm. Nhìn cụ thể vào kích thước bộ đệm 1.000 với các kích cỡ chèn khác nhau, tôi nhận được các kết quả sau (thử từng kích thước lô 50 lần và tổng hợp các kết quả như dưới đây - tất cả các lần trong μ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 |
+------------+-----------+-----------+-----------+-----------+-----------+-----------+

Đối với kích thước lô lớn hơn, IDENTITY phiên bản thường có vẻ nhanh hơn .

Cuốn sách Truy vấn TSQL cũng giải thích tại sao IDENTITYcó thể có lợi thế về hiệu suất theo trình tự.

Bảng IDENTITYlà cụ thể và SEQUENCEkhông. Nếu thảm họa xảy ra với mid insert trước khi bộ đệm log bị xóa thì không có vấn đề gì nếu nhận dạng được khôi phục là trước đó vì quá trình khôi phục cũng sẽ hoàn tác chèn, vì vậy SQL Server không buộc xóa bộ đệm log trên mỗi nhận dạng bộ nhớ cache liên quan đến đĩa ghi. Tuy nhiên đối với Sequence này được thi hành vì giá trị có thể được sử dụng cho bất kỳ mục đích nào - bao gồm cả bên ngoài cơ sở dữ liệu. Vì vậy, trong ví dụ trên với một triệu lần chèn và kích thước bộ đệm là 1.000, đây là một nghìn lần xóa nhật ký.

Kịch bản để tái tạo

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;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.