Trong SQL Server lưu trữ theo định hướng hàng cả các chỉ mục được nhóm và không được bao gồm được tổ chức dưới dạng cây B.
( Nguồn hình ảnh )
Sự khác biệt chính giữa các chỉ mục được phân cụm và các chỉ mục không được phân cụm là mức độ lá của chỉ mục được phân cụm là bảng. Điều này có hai hàm ý.
- Các hàng trên các trang lá chỉ mục được nhóm luôn chứa một cái gì đó cho mỗi cột (không thưa thớt) trong bảng (có thể là giá trị hoặc con trỏ tới giá trị thực).
- Chỉ mục cụm là bản sao chính của bảng.
Các chỉ mục không được nhóm cũng có thể thực hiện điểm 1 bằng cách sử dụng INCLUDE
mệnh đề (Kể từ SQL Server 2005) để bao gồm rõ ràng tất cả các cột không khóa nhưng chúng là các biểu diễn phụ và luôn có một bản sao khác của dữ liệu xung quanh (chính bảng).
CREATE TABLE T
(
A INT,
B INT,
C INT,
D INT
)
CREATE UNIQUE CLUSTERED INDEX ci ON T(A,B)
CREATE UNIQUE NONCLUSTERED INDEX nci ON T(A,B) INCLUDE (C,D)
Hai chỉ số trên sẽ gần giống nhau. Với các trang chỉ mục cấp cao hơn chứa các giá trị cho các cột chính A,B
và các trang cấp độ lá chứaA,B,C,D
Chỉ có thể có một chỉ mục được nhóm trên mỗi bảng, vì bản thân các hàng dữ liệu có thể được sắp xếp theo một thứ tự.
Trích dẫn trên từ sách SQL Server trực tuyến gây ra nhiều nhầm lẫn
Theo ý kiến của tôi, nó sẽ tốt hơn nhiều.
Chỉ có thể có một chỉ mục được nhóm trên mỗi bảng, bởi vì các hàng cấp độ lá của chỉ mục được phân cụm là các hàng của bảng.
Các trích dẫn trực tuyến sách không phải là không chính xác nhưng bạn nên rõ ràng rằng "sắp xếp" của cả hai chỉ số không phân cụm và phân cụm là logic không phải là vật lý. Nếu bạn đọc các trang ở cấp độ lá bằng cách theo danh sách được liên kết và đọc các hàng trên trang theo thứ tự mảng vị trí thì bạn sẽ đọc các hàng chỉ mục theo thứ tự được sắp xếp nhưng về mặt vật lý có thể không được sắp xếp. Người ta thường cho rằng với một chỉ mục được nhóm, các hàng luôn được lưu trữ vật lý trên đĩa theo cùng thứ tự với khóa chỉ mục là sai.
Đây sẽ là một thực hiện vô lý. Ví dụ: nếu một hàng được chèn vào giữa bảng 4GB thì SQL Server không phải sao chép 2GB dữ liệu trong tệp để nhường chỗ cho hàng mới được chèn.
Thay vào đó một sự phân chia trang xảy ra. Mỗi trang ở cấp độ lá của cả hai chỉ mục được phân cụm và không phân cụm có địa chỉ ( File:Page
) của trang tiếp theo và trước đó theo thứ tự khóa logic. Các trang này không cần phải liền kề hoặc theo thứ tự chính.
ví dụ: chuỗi trang được liên kết có thể là 1:2000 <-> 1:157 <-> 1:7053
Khi xảy ra sự phân chia trang, một trang mới được phân bổ từ bất kỳ nơi nào trong nhóm fileg (từ một phạm vi hỗn hợp, cho các bảng nhỏ hoặc phạm vi thống nhất không trống thuộc về đối tượng đó hoặc phạm vi thống nhất mới được phân bổ). Điều này thậm chí có thể không nằm trong cùng một tệp nếu nhóm tệp chứa nhiều hơn một.
Mức độ mà trật tự logic và sự liên tục khác với phiên bản vật lý được lý tưởng hóa là mức độ phân mảnh logic.
Trong một cơ sở dữ liệu mới được tạo với một tệp duy nhất tôi đã chạy như sau.
CREATE TABLE T
(
X TINYINT NOT NULL,
Y CHAR(3000) NULL
);
CREATE CLUSTERED INDEX ix
ON T(X);
GO
--Insert 100 rows with values 1 - 100 in random order
DECLARE @C1 AS CURSOR,
@X AS INT
SET @C1 = CURSOR FAST_FORWARD
FOR SELECT number
FROM master..spt_values
WHERE type = 'P'
AND number BETWEEN 1 AND 100
ORDER BY CRYPT_GEN_RANDOM(4)
OPEN @C1;
FETCH NEXT FROM @C1 INTO @X;
WHILE @@FETCH_STATUS = 0
BEGIN
INSERT INTO T (X)
VALUES (@X);
FETCH NEXT FROM @C1 INTO @X;
END
Sau đó kiểm tra bố cục trang với
SELECT page_id,
X,
geometry::Point(page_id, X, 0).STBuffer(1)
FROM T
CROSS APPLY sys.fn_PhysLocCracker( %% physloc %% )
ORDER BY page_id
Kết quả ở khắp mọi nơi. Hàng đầu tiên theo thứ tự chính (có giá trị 1 - được tô sáng bằng mũi tên bên dưới) nằm trên gần trang vật lý cuối cùng.
Sự phân mảnh có thể được giảm hoặc loại bỏ bằng cách xây dựng lại hoặc sắp xếp lại một chỉ mục để tăng mối tương quan giữa trật tự logic và trật tự vật lý.
Sau khi chạy
ALTER INDEX ix ON T REBUILD;
Tôi đã nhận được sau đây
Nếu bảng không có chỉ mục cụm thì nó được gọi là heap.
Các chỉ mục không được nhóm có thể được xây dựng trên một heap hoặc một chỉ mục được nhóm. Chúng luôn chứa một bộ định vị hàng trở lại bảng cơ sở. Trong trường hợp của một đống, đây là một định danh hàng vật lý (thoát) và bao gồm ba thành phần (Tệp: Trang: Khe cắm). Trong trường hợp chỉ mục Clustered, bộ định vị hàng là logic (khóa chỉ mục được nhóm).
Đối với trường hợp sau, nếu chỉ mục không được nhóm đã tự nhiên bao gồm (các) cột khóa CI hoặc là cột khóa NCI hoặc INCLUDE
cột -d thì không có gì được thêm vào. Mặt khác, (các) cột khóa CI bị thiếu âm thầm được thêm vào NCI.
SQL Server luôn đảm bảo rằng các cột chính là duy nhất cho cả hai loại chỉ mục. Tuy nhiên, cơ chế này được thi hành cho các chỉ mục không được khai báo là khác nhau duy nhất giữa hai loại chỉ mục.
Các chỉ mục được nhóm được uniquifier
thêm vào cho bất kỳ hàng nào có giá trị chính trùng lặp với một hàng hiện có. Đây chỉ là một số nguyên tăng dần.
Đối với các chỉ mục không được phân cụm không được khai báo là SQL Server duy nhất âm thầm thêm trình định vị hàng vào khóa chỉ mục không được phân cụm. Điều này áp dụng cho tất cả các hàng, không chỉ những hàng thực sự trùng lặp.
Danh pháp phân cụm so với không phân cụm cũng được sử dụng cho các chỉ mục lưu trữ cột. Các cải tiến giấy cho các trạng thái lưu trữ cột của máy chủ SQL
Mặc dù dữ liệu lưu trữ cột không thực sự được "phân cụm" trên bất kỳ khóa nào, chúng tôi đã quyết định giữ lại quy ước SQL Server truyền thống về việc chỉ mục chính là một chỉ mục được nhóm.