ĐẦU TIÊN
Bạn có thể không cần tất cả ba cột: old_id
, external_id
, new_id
. Các new_id
cột, là một IDENTITY
, sẽ có một giá trị mới được tạo ra cho mỗi hàng, ngay cả khi bạn chèn vào external_id
. Nhưng, giữa old_id
và external_id
, những thứ đó khá nhiều loại trừ lẫn nhau: hoặc đã có một old_id
giá trị hoặc cột đó, theo quan niệm hiện tại, sẽ chỉ là NULL
nếu sử dụng external_id
hoặc new_id
. Vì bạn sẽ không thêm id "bên ngoài" mới vào một hàng đã tồn tại (tức là một id có old_id
giá trị) và sẽ không có bất kỳ giá trị mới nào xuất hiện old_id
, nên có thể có một cột được sử dụng cho cả hai mục đích
Vì vậy, hãy thoát khỏi external_id
cột và đổi tên old_id
thành một cái gì đó giống như old_or_external_id
hoặc bất cứ điều gì. Điều này không yêu cầu bất kỳ thay đổi thực sự đối với bất cứ điều gì, nhưng làm giảm một số biến chứng. Nhiều nhất bạn có thể cần gọi cột external_id
, ngay cả khi nó chứa các giá trị "cũ", nếu mã ứng dụng đã được viết để chèn vào external_id
.
Điều đó làm giảm cấu trúc mới chỉ là:
PkId AS AS COALESCE(old_or_external_id, new_id, -1) PERSISTED NOT NULL,
old_or_external_id INT NULL, -- values from existing record OR passed in from app
new_id INT IDENTITY(2000000, 1) NOT NULL
Bây giờ bạn chỉ thêm 8 byte mỗi hàng thay vì 12 byte (giả sử rằng bạn không sử dụng SPARSE
tùy chọn hoặc Nén dữ liệu). Và bạn không cần thay đổi bất kỳ mã, mã T-SQL hoặc mã ứng dụng nào.
THỨ HAI
Tiếp tục con đường đơn giản hóa này, chúng ta hãy nhìn vào những gì chúng ta còn lại:
- Các
old_or_external_id
cột hoặc có giá trị đã có, hoặc sẽ được cung cấp một giá trị mới từ ứng dụng, hoặc sẽ bị bỏ lại như NULL
.
- Di
new_id
chúc luôn có một giá trị mới được tạo, nhưng giá trị đó sẽ chỉ được sử dụng nếu old_or_external_id
cột là NULL
.
Không bao giờ có lúc bạn sẽ cần các giá trị trong cả hai old_or_external_id
và new_id
. Có, sẽ có lúc cả hai cột có giá trị do new_id
là một IDENTITY
, nhưng những new_id
giá trị đó bị bỏ qua. Một lần nữa, hai lĩnh vực này là loại trừ lẫn nhau. Giờ thì sao?
Bây giờ chúng ta có thể xem xét lý do tại sao chúng ta cần external_id
ở nơi đầu tiên. Xem xét rằng có thể chèn vào một IDENTITY
cột bằng cách sử dụng SET IDENTITY_INSERT {table_name} ON;
, bạn có thể thoát khỏi việc không thực hiện thay đổi lược đồ nào và chỉ sửa đổi mã ứng dụng của bạn để bọc các INSERT
câu lệnh / thao tác SET IDENTITY_INSERT {table_name} ON;
và SET IDENTITY_INSERT {table_name} OFF;
câu lệnh. Sau đó, bạn cần xác định phạm vi bắt đầu nào để đặt lại IDENTITY
cột thành (đối với các giá trị mới được tạo) vì nó sẽ cần cao hơn các giá trị mà mã ứng dụng sẽ chèn vì việc chèn giá trị cao hơn sẽ khiến giá trị được tạo tự động tiếp theo lớn hơn giá trị MAX hiện tại. Nhưng bạn luôn có thể chèn một giá trị nằm dưới giá trị IDENT_CURRENT .
Việc kết hợp các cột old_or_external_id
và new_id
cột cũng không làm tăng cơ hội chạy vào tình huống giá trị chồng chéo giữa các giá trị được tạo tự động và giá trị do ứng dụng tạo ra do ý định có các cột 2 hoặc thậm chí 3, là kết hợp chúng thành một giá trị Khóa chính, và đó luôn là những giá trị độc nhất
Trong phương pháp này, bạn chỉ cần:
Để lại các bảng như:
PkId INT IDENTITY(1,1) PRIMARY KEY
Điều này thêm 0 byte vào mỗi hàng, thay vì 8 hoặc thậm chí 12.
- Xác định phạm vi bắt đầu cho các giá trị do ứng dụng tạo. Giá trị này sẽ lớn hơn giá trị MAX hiện tại trong mỗi bảng, nhưng nhỏ hơn giá trị tối thiểu sẽ trở thành giá trị tối thiểu cho các giá trị được tạo tự động.
- Xác định giá trị nào phạm vi được tạo tự động sẽ bắt đầu tại. Cần có nhiều phòng giữa giá trị MAX hiện tại và nhiều phòng để phát triển, biết ở giới hạn trên chỉ là hơn 2,14 tỷ. Sau đó, bạn có thể đặt giá trị hạt giống tối thiểu mới này thông qua DBCC CHECKIDENT .
- Bọc mã ứng dụng INSERTs trong
SET IDENTITY_INSERT {table_name} ON;
và SET IDENTITY_INSERT {table_name} OFF;
báo cáo.
THỨ HAI, Phần B
Một biến thể của cách tiếp cận được ghi chú trực tiếp ở trên sẽ có các giá trị chèn mã ứng dụng bắt đầu bằng -1 và đi xuống từ đó. Điều này để lại các IDENTITY
giá trị như là những người duy nhất đi lên . Lợi ích ở đây là bạn không chỉ không làm phức tạp lược đồ, bạn cũng không cần lo lắng về việc chạy vào các ID chồng chéo (nếu các giá trị do ứng dụng tạo ra chạy trong phạm vi được tạo tự động mới). Đây chỉ là một tùy chọn nếu bạn chưa sử dụng các giá trị ID âm (và dường như khá hiếm khi mọi người sử dụng các giá trị âm trên các cột được tạo tự động, do đó, điều này sẽ có khả năng rõ ràng trong hầu hết các tình huống).
Trong phương pháp này, bạn chỉ cần:
Để lại các bảng như:
PkId INT IDENTITY(1,1) PRIMARY KEY
Điều này thêm 0 byte vào mỗi hàng, thay vì 8 hoặc thậm chí 12.
- Phạm vi bắt đầu cho các giá trị do ứng dụng tạo ra sẽ là
-1
.
- Bọc mã ứng dụng INSERTs trong
SET IDENTITY_INSERT {table_name} ON;
và SET IDENTITY_INSERT {table_name} OFF;
báo cáo.
Ở đây bạn vẫn cần phải thực hiện IDENTITY_INSERT
, nhưng: bạn không thêm bất kỳ cột mới nào, không cần "đổi mới" bất kỳ IDENTITY
cột nào và không có nguy cơ chồng chéo trong tương lai.
THỨ HAI, Phần 3
Một biến thể cuối cùng của phương pháp này là có thể hoán đổi các IDENTITY
cột và thay vào đó sử dụng Chuỗi . Lý do để thực hiện phương pháp này là để có thể có các giá trị chèn mã ứng dụng là: dương, trên phạm vi được tạo tự động (không phải bên dưới) và không cần SET IDENTITY_INSERT ON / OFF
.
Trong phương pháp này, bạn chỉ cần:
- Tạo chuỗi bằng CREATE SEQUENCE
Sao chép IDENTITY
cột sang một cột mới không có thuộc IDENTITY
tính, nhưng có DEFAULT
ràng buộc bằng cách sử dụng chức năng GIÁ TRỊ TIẾP THEO :
PkId INT PRIMARY KEY CONSTRAINT [DF_TableName_NextID] DEFAULT (NEXT VALUE FOR...)
Điều này thêm 0 byte vào mỗi hàng, thay vì 8 hoặc thậm chí 12.
- Phạm vi bắt đầu cho các giá trị được tạo bởi ứng dụng sẽ vượt xa những gì bạn nghĩ rằng các giá trị được tạo tự động sẽ tiếp cận.
- Bọc mã ứng dụng INSERTs trong
SET IDENTITY_INSERT {table_name} ON;
và SET IDENTITY_INSERT {table_name} OFF;
báo cáo.
TUY NHIÊN , do yêu cầu mã với một SCOPE_IDENTITY()
hoặc @@IDENTITY
vẫn hoạt động đúng, chuyển sang Chuỗi hiện không phải là một tùy chọn vì dường như không có chức năng nào tương đương với các hàm đó cho Chuỗi :-(. Buồn!