Cú pháp SQL Server để tạo một chỉ mục cụm cũng là một khóa chính là:
CREATE TABLE dbo.c
(
c1 INT NOT NULL,
c2 INT NOT NULL,
CONSTRAINT PK_c
PRIMARY KEY CLUSTERED (c1, c2)
);
Theo như nhận xét của bạn: "tạo PK sử dụng chỉ mục được đặt tên", đoạn mã trên sẽ dẫn đến chỉ mục khóa chính được đặt tên là "PK_c".
Khóa chính và khóa phân cụm không phải là cùng một cột. Bạn có thể định nghĩa chúng một cách riêng biệt. Trong ví dụ trên, thay đổi CLUSTERED
từ khóa thành NONCLUSTERED
, và sau đó chỉ cần thêm một chỉ mục được nhóm bằng CREATE INDEX
cú pháp:
CREATE TABLE dbo.c
(
c1 INT,
c2 INT,
CONSTRAINT PK_c
PRIMARY KEY NONCLUSTERED (c1, c2)
);
CREATE CLUSTERED INDEX CX_c ON dbo.c (c2);
Trong SQL Server, chỉ mục được nhóm là bảng, chúng là một và giống nhau. Một chỉ mục cụm xác định thứ tự logic của các hàng được lưu trữ trong bảng. Trong ví dụ đầu tiên của tôi, các hàng được lưu trữ theo thứ tự các giá trị của cột c1
và c2
cột. Vì khóa phân cụm cũng được định nghĩa là khóa chính, nên sự kết hợp c1
và c2
phải là toàn bảng duy nhất.
Trong ví dụ thứ hai, khóa chính bao gồm các cột c1
và c2
cột, tuy nhiên khóa phân cụm chỉ là c2
cột. Vì tôi không chỉ định UNIQUE
thuộc tính trong CREATE INDEX
câu lệnh, khóa cluster ( c2
) không bắt buộc phải là duy nhất trên bảng. Một "uniquifier" sẽ được SQL Server tự động tạo và gắn vào các giá trị trong c2
cột để tạo khóa phân cụm. Khóa phân cụm này, vì nó là duy nhất, sau đó sẽ được sử dụng làm id hàng trong các chỉ mục khác được tạo trên bảng.
Để chứng minh khóa phân cụm điều khiển bố cục các hàng trong bộ lưu trữ, bạn có thể sử dụng chức năng không có giấy tờ , fn_PhysLocCracker(%%PHYSLOC%%)
. Đoạn mã sau cho thấy các hàng được đặt trên đĩa theo thứ tự của c2
cột, mà tôi đã xác định là khóa phân cụm:
USE tempdb;
CREATE TABLE dbo.PKTest
(
c1 INT NOT NULL
, c2 INT NOT NULL
, c3 VARCHAR(256) NOT NULL
);
ALTER TABLE PKTest
ADD CONSTRAINT PK_PKTest
PRIMARY KEY NONCLUSTERED (c1, c2);
CREATE CLUSTERED INDEX CX_PKTest
ON dbo.PKTest(c2);
TRUNCATE TABLE dbo.PKTest;
INSERT INTO dbo.PKTest (c1, c2, c3)
SELECT TOP(25) o1.object_id / o2.object_id, o2.object_id, o1.name + '.' + o2.name
FROM sys.objects o1
, sys.objects o2
WHERE o1.object_id >0
and o2.object_id > 0;
SELECT plc.file_id
, plc.page_id
, plc.slot_id
, pk.*
FROM dbo.PKTest pk
CROSS APPLY fn_PhysLocCracker(%%PHYSLOC%%) plc;
Các kết quả từ tempdb của tôi là:
Trong hình trên, ba cột đầu tiên được xuất ra từ fn_PhysLocCracker
hàm, hiển thị thứ tự vật lý của các hàng trên đĩa. Bạn có thể thấy slot_id
giá trị tăng bước khóa với c2
giá trị, đó là khóa phân cụm. Chỉ mục khóa chính lưu trữ các hàng theo một thứ tự khác, có thể được nhìn thấy bằng cách buộc SQL Server trả về kết quả từ việc quét khóa chính:
SELECT pkt.c1
, pkt.c2
FROM dbo.PKTest pkt WITH (INDEX = PK_PKTest, FORCESCAN);
Lưu ý, tôi đã không sử dụng một ORDER BY
mệnh đề trong tuyên bố trên vì tôi đang cố gắng hiển thị thứ tự của các mục trong chỉ mục khóa chính.
Đầu ra từ truy vấn trên là:
Nhìn vào fn_PhysLocCracker
hàm, chúng ta có thể thấy thứ tự vật lý của chỉ số khóa chính.
SELECT plc.file_id
, plc.page_id
, plc.slot_id
, pkt.c1
, pkt.c2
FROM dbo.PKTest pkt WITH (INDEX = PK_PKTest, FORCESCAN)
CROSS APPLY fn_PhysLocCracker(%%PHYSLOC%%) plc;
Vì chúng tôi chỉ đọc từ chính chỉ mục, tức là không có cột nào bên ngoài chỉ mục được tham chiếu trong truy vấn, nên các %%PHYSLOC%%
giá trị đại diện cho các trang trong chính chỉ mục.
Kết quả:
create table c (c1 int not null primary key, c2 int)