Nhiều cột kiểu dữ liệu BIT trong cùng một bảng


7

Xem xét các thông tin sau đến từ các trang tài liệu Microsoft SQL:

Công cụ cơ sở dữ liệu SQL Server tối ưu hóa việc lưu trữ các cột bit. Nếu có 8 hoặc ít hơn các cột bit trong một bảng, các cột được lưu trữ dưới dạng 1 byte. Nếu có từ 9 đến 16 cột, các cột được lưu dưới dạng 2 byte, v.v.

Xem: https://docs.microsoft.com/en-us/sql/t-sql/data-types/bit-transact-sql?view=sql-server-2017

Vì vậy, nếu tôi tạo một bảng mới như thế này:

CREATE TABLE MyTable (
    Id int PRIMARY KEY,
    Value1 bit,
    Value2 bit,
    Value3 bit,
    Value4 bit,
    Value5 bit,
    Value6 bit,
    Value7 bit,
    Value8 bit)

... sau đó tất cả các cột bit (Value1, Value2, ... Value8) trong một hàng sẽ chiếm một byte. Hoặc là?

Khi chúng ta xem xét kỹ hơn, trường Value1 của một hàng có thể có các giá trị 0, 1 hoặc NULL bên trong. Điều này có nghĩa là trường thực sự có giá trị 3 trạng thái hoặc giá trị ternary. 2 giá trị như vậy có thể đại diện cho từ điển của 3 * 3 = 9 giá trị. 8 giá trị như vậy là một từ điển của 6561 giá trị.

Nếu chúng ta đang nghĩ về dấu chân bộ nhớ của một hàng như vậy, 8 bit sẽ chiếm một byte. Điều này có nghĩa là một byte này mã hóa 6561 giá trị thay vì 256 giá trị. Điều này rõ ràng là sai.

Vì vậy, hoặc các tài liệu MS SQL là sai lệch hoặc chúng ta đang nói về một số tính toán lượng tử ở đây. Tất nhiên đó là câu hỏi trước đây, nhưng điều tôi thực sự muốn biết là câu trả lời cho câu hỏi này: làm thế nào các bit nullable (và tất nhiên các bit SQL Server là null theo mặc định) thực sự được lưu trữ trong các cấu trúc cơ sở của SQL Server?


1
Tốt nhất đừng nghĩ về NULL như một giá trị của thuộc tính mà là siêu dữ liệu về trạng thái của thuộc tính đó.
Michael Green

Câu trả lời:


13

Đối với trường có độ dài cố định (chẳng hạn như giá trị bit), trường sẽ luôn chiếm cùng một dung lượng - trong trường hợp của bạn là một bit.

Các bitmap NULL là ở hàng dữ liệu riêng của mình - điều này được lưu trữ cho dù một lĩnh vực cụ thể được coi là NULL hay không. Do đó, trường chỉ phải lưu trữ hai giá trị - 1 hoặc 0 - bitmap NULL xử lý xem trường có thực sự được đặt thành NULL hay không.

Bitmap NULL có một bit cho mỗi cột trong bảng bất kể cột đó là nullable và điều này có chứa "giá trị thứ ba" mà bạn đề cập. Một lần nữa, không gian cho bitmap null được làm tròn thành số byte nguyên.

Đoạn mã sau trình bày cách SQL Server lưu trữ bitmap NULL - bạn sẽ cần thay thế số trang nếu bạn tự chạy nó.

CREATE TABLE TestNullBitmap (
    TestText CHAR(10) NULL
    )
GO

INSERT INTO [dbo].[TestNullBitmap] ([TestText])
VALUES
('hello'),
('hello2'),
(NULL);

--Grab the page number
DBCC IND ([TestDb],TestNullBitmap,-1);
GO

--Use the page number from DBCC IND
DBCC PAGE ([TestDb],1,631032,3) WITH TABLERESULTS;
GO

Đối với tôi, tôi nhận được các kết quả sau cho ba hàng dữ liệu:

0000000000000000: 10000e00 68656c6c 6f202020 20200100 00 .... xin chào ...

0000000000000000: 10000e00 68656c6c 6f322020 20200100 00 .... xin chào ...

0000000000000000: 10000e00 68656c6c 6f322020 20200100 01 .... xin chào ...

Bitmap NULL là sự thay đổi của giá trị byte cuối cùng đó - đọc trong Little Endian biểu diễn nhị phân là 0000 0001(IE Cột đầu tiên là NULL)

Khá thú vị, bạn cũng có thể thấy rằng hệ thống đã lưu trữ giá trị từ INSERT trước đó dưới dạng dữ liệu thực tế cho trường có độ dài cố định - chứ không phải là 0.


Không có gì lãng phí khi có một bit trong bitmap NULL cho các cột không nullable? Điều này được thực hiện để cho phép thay đổi thuộc tính này mà không phải xây dựng lại bảng?
Barmar

@barmar Tôi có xu hướng đồng ý - đó có thể là câu hỏi của riêng nó.
George.Palacios
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.