Khoảng trống bất ngờ trong cột IDENTITY


16

Tôi đang cố gắng tạo số thứ tự mua hàng duy nhất bắt đầu từ 1 và tăng thêm 1. Tôi có một bảng PONumber được tạo bằng tập lệnh này:

CREATE TABLE [dbo].[PONumbers]
(
  [PONumberPK] [int] IDENTITY(1,1) NOT NULL,
  [NewPONo] [bit] NOT NULL,
  [DateInserted] [datetime] NOT NULL DEFAULT GETDATE(),
  CONSTRAINT [PONumbersPK] PRIMARY KEY CLUSTERED ([PONumberPK] ASC)    
);

Và một thủ tục được lưu trữ được tạo bằng tập lệnh này:

CREATE PROCEDURE [dbo].[GetPONumber] 
AS
BEGIN
    SET NOCOUNT ON;

    INSERT INTO [dbo].[PONumbers]([NewPONo]) VALUES(1);
    SELECT SCOPE_IDENTITY() AS PONumber;
END

Tại thời điểm tạo ra, điều này hoạt động tốt. Khi thủ tục được lưu trữ chạy, nó bắt đầu ở số mong muốn và tăng thêm 1.

Điều kỳ lạ là, nếu tôi tắt hoặc ngủ đông máy tính của mình, thì lần tiếp theo thủ tục chạy, trình tự đã tiến gần 1000.

Xem kết quả dưới đây:

Số PO

Bạn có thể thấy rằng con số đã nhảy từ 8 đến 1002!

  • Tại sao chuyện này đang xảy ra?
  • Làm thế nào để tôi đảm bảo rằng những con số không bị bỏ qua như vậy?
  • Tất cả những gì tôi cần là cho SQL tạo ra các số đó là:
    • a) Đảm bảo duy nhất.
    • b) tăng theo số lượng mong muốn.

Tôi thừa nhận tôi không phải là một chuyên gia SQL. Tôi có hiểu nhầm những gì SCOPE_IDENTITY () không? Tôi có nên sử dụng một cách tiếp cận khác? Tôi đã xem xét các trình tự trong SQL 2012+, nhưng Microsoft nói rằng chúng không được đảm bảo là duy nhất theo mặc định.

Câu trả lời:


23

Đây là một vấn đề đã biết và dự kiến ​​- cách các cột IDENTITY được quản lý bởi SQL Server đã thay đổi trong SQL Server 2012 ( một số nền tảng ); theo mặc định, nó sẽ lưu trữ 1000 giá trị và nếu bạn khởi động lại SQL Server, khởi động lại máy chủ, không thành công, v.v. nó sẽ phải loại bỏ 1000 giá trị đó, bởi vì nó sẽ không có cách đáng tin cậy để biết có bao nhiêu trong số chúng thực sự cấp. Điều này được ghi lại ở đây . Có một cờ theo dõi thay đổi hành vi này sao cho mọi nhiệm vụ IDENTITY được ghi lại *, ngăn chặn các khoảng trống cụ thể đó (nhưng không phải là các khoảng trống từ các lần khôi phục hoặc xóa); tuy nhiên, điều quan trọng cần lưu ý là điều này có thể khá tốn kém về mặt hiệu suất, vì vậy tôi thậm chí sẽ không đề cập đến cờ theo dõi cụ thể ở đây.

* (Cá nhân, tôi nghĩ rằng đây là một vấn đề kỹ thuật có thể được giải quyết khác nhau, nhưng vì tôi không viết công cụ, tôi không thể thay đổi điều đó.)

Để rõ ràng về cách IDENTITY và SEQUENCE hoạt động:

  • Không được đảm bảo là duy nhất (bạn cần thực thi điều đó ở cấp độ bảng, sử dụng khóa chính hoặc ràng buộc duy nhất)
  • Không được đảm bảo là không có khoảng cách (ví dụ, bất kỳ rollback hoặc xóa, sẽ tạo ra một khoảng cách, vấn đề cụ thể này mặc dù)

Tính độc đáo dễ thực thi. Tránh những khoảng trống là không. Bạn cần xác định tầm quan trọng của mình để tránh những khoảng trống này (về lý thuyết, bạn không nên quan tâm đến khoảng trống, vì các giá trị IDENTITY / SEQUENCE phải là các khóa thay thế vô nghĩa). Nếu nó rất quan trọng, thì bạn không nên sử dụng một trong hai cách thực hiện mà nên cuộn trình tạo trình tự tuần tự của riêng bạn (xem một số ý tưởng ở đây , ở đâyở đây ) - chỉ cần lưu ý rằng nó sẽ giết đồng thời.

Rất nhiều nền tảng về "vấn đề" này:


Câu trả lời này (ngoại trừ phần "cờ theo dõi") cũng áp dụng cho hầu hết các cơ sở dữ liệu SQL khác (những cơ sở dữ liệu có trình tự nào).
mustaccio 7/07/2015

Cảm ơn câu trả lời. Tính duy nhất là yêu cầu quan trọng nhất. Khoảng trống không phải là vấn đề lớn, miễn là chúng không lớn. ví dụ: đi từ 1 đến 4 sẽ được chấp nhận, nhưng từ 4 đến 1003 thì không.
Ege Ersoz 7/07/2015

1
Phiên bản ngắn: các giá trị ID sẽ được sử dụng làm số thứ tự mua hàng. Khách hàng chạy các báo cáo hàng tháng và muốn có thể nhanh chóng cho biết có bao nhiêu PO đã được gửi trong tháng đó chỉ bằng cách xem số PO. Vì vậy, chúng tôi không thể tăng nó thêm 1000 (có bảo trì hàng tuần trong đó tất cả các máy chủ, bao gồm cả máy chủ DB, được khởi động lại).
Ege Ersoz 7/07/2015

3
Tại sao bạn không cung cấp cho họ một báo cáo rất dễ dàng chỉ sử dụng ROW_NUMBER () QUÁ (THAM GIA THEO ĐẶT HÀNG theo ID)? Một lần nữa, số ID sẽ là vô nghĩa, đó là một cách khủng khiếp để nhãn cầu có bao nhiêu đơn đặt hàng đã được thực hiện. Điều gì xảy ra nếu bạn có một lỗi trong mã xóa 1000 hàng hoặc khôi phục lại 275 giao dịch hoặc 500 đơn hàng bị hủy hợp pháp?
Aaron Bertrand

1
@Ege: "... cho biết có bao nhiêu ... chỉ bằng cách nhìn vào số PO". Người dùng của bạn sẽ thất vọng. Giá trị danh tính đơn giản là không hoạt động theo cách đó, bạn cũng không nên đưa ra bất kỳ giả định nào như vậy. Độc nhất? Đúng. Liên tiếp? Không. Cách chính xác để đếm số PO được gửi trong một tháng là ... để đếm số PO được tăng trong tháng đó, dựa trên một số trường Ngày [không thể thay đổi] trong mỗi bản ghi.
Phill W.

-4

Đây là vấn đề của SQL Server. Tất cả những gì bạn có thể làm là lấy lại cột.

xóa các mục với id cột sai. Thay đổi danh tính cột. Và sau đó mục tiếp theo có ID thích hợp với nó.

Nhận dạng Reseed bằng cách sử dụng lệnh sql sau: DBCC CHECKIDENT ('YOUR_TABLE_NAME', RESEED, 9)- 9 là Id chính xác cuối cùng


1
Bạn có ý nghĩa gì với "xóa các mục"?
ypercubeᵀᴹ

2
Hmmm .. dường như xóa các mục có thể dẫn đến mất dữ liệu.
Michael Green
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.