Câu hỏi rất hay vì nó là một khái niệm quan trọng như vậy. Đây là một chủ đề lớn và những gì tôi sẽ chỉ cho bạn là một sự đơn giản hóa để bạn có thể hiểu các khái niệm cơ bản.
Thứ nhất khi bạn nhìn thấy chỉ số clustered nghĩ bàn . Trong máy chủ SQL nếu một bảng không chứa chỉ mục được nhóm thì đó là một đống. Tạo một chỉ mục cụm trên bảng thực sự biến đổi bảng thành cấu trúc kiểu b-cây. Chỉ mục được nhóm của bạn LÀ bảng của bạn, nó không tách rời khỏi bảng
Đã bao giờ tự hỏi tại sao bạn chỉ có thể có một chỉ số cụm? Chà, nếu chúng ta có hai chỉ mục được nhóm, chúng ta sẽ cần hai bản sao của bảng. Nó chứa dữ liệu sau khi tất cả.
Tôi sẽ cố gắng giải thích điều này bằng cách sử dụng một ví dụ đơn giản.
LƯU Ý: Tôi đã tạo bảng trong ví dụ này và điền vào đó với hơn 3 triệu mục ngẫu nhiên. Sau đó chạy các truy vấn thực tế và dán các kế hoạch thực hiện ở đây.
Những gì bạn thực sự cần phải nắm bắt là ký hiệu O hoặc hiệu quả hoạt động . Giả sử bạn có bảng sau.
CREATE TABLE [dbo].[Customer](
[CustomerID] [int] IDENTITY(1,1) NOT NULL,
[CustomerName] [varchar](100) NOT NULL,
[CustomerSurname] [varchar](100) NOT NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED
(
[CustomerID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF
, IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS = ON
, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Vì vậy, ở đây chúng ta có bảng cơ bản với một khóa được phân cụm trên CustomerID (Khóa chính được phân cụm theo mặc định). Do đó, bảng được sắp xếp / sắp xếp dựa trên khóa chính ID khách hàng. Các cấp độ trung gian sẽ chứa các giá trị CustomerID. Các trang dữ liệu sẽ chứa toàn bộ hàng do đó là hàng của bảng.
Chúng tôi cũng sẽ tạo một chỉ mục không được nhóm trên trường Tên khách hàng. Các mã sau đây sẽ làm điều đó.
CREATE NONCLUSTERED INDEX [ix_Customer_CustomerName] ON [dbo].[Customer]
(
[CustomerName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF
, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF
, DROP_EXISTING = OFF, ONLINE = OFF
, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
Vì vậy, trong chỉ mục này, bạn sẽ tìm thấy trên các trang dữ liệu / nút mức lá một con trỏ tới các mức trung gian trong chỉ mục được nhóm. Chỉ mục được sắp xếp / sắp xếp xung quanh trường CustomerName. Do đó, mức trung gian chứa các giá trị CustomerName và cấp độ lá sẽ chứa con trỏ (các giá trị con trỏ này thực sự là các giá trị khóa chính hoặc cột CustomerID).
Đúng vậy nếu chúng ta thực hiện truy vấn sau:
SELECT * FROM Customer WHERE CustomerID = 1
SQL có thể sẽ đọc chỉ mục được nhóm thông qua một hoạt động tìm kiếm. Một hoạt động tìm kiếm là một tìm kiếm nhị phân hiệu quả hơn nhiều so với quét là một tìm kiếm tuần tự. Vì vậy, trong ví dụ trên của chúng tôi, chỉ mục được đọc và bằng cách sử dụng SQL tìm kiếm nhị phân có thể loại bỏ dữ liệu không phù hợp với tiêu chí mà chúng tôi đang tìm kiếm. Xem ảnh chụp màn hình đính kèm cho kế hoạch truy vấn.
Vì vậy, số lượng hoạt động hoặc ký hiệu O cho hoạt động tìm kiếm như sau:
- Thực hiện tìm kiếm nhị phân trên chỉ mục cụm bằng cách so sánh giá trị được tìm kiếm với các giá trị ở cấp độ trung gian.
- Trả về các giá trị khớp (nhớ vì chỉ mục được nhóm có tất cả dữ liệu trong đó có thể trả về tất cả các cột từ chỉ mục vì đây là dữ liệu hàng)
Vì vậy, nó là hai hoạt động. Tuy nhiên nếu chúng tôi thực hiện truy vấn sau:
SELECT * FROM Customer WHERE CustomerName ='John'
Bây giờ SQL sẽ sử dụng chỉ mục không được nhóm trên Tên khách hàng để thực hiện tìm kiếm. Tuy nhiên vì đây là một chỉ mục không được nhóm nên nó không chứa tất cả dữ liệu trong hàng.
Vì vậy, SQL sẽ thực hiện tìm kiếm ở các cấp độ trung gian để tìm các bản ghi khớp với nhau sau đó thực hiện tra cứu bằng cách sử dụng các giá trị được trả về để thực hiện một tìm kiếm khác trên chỉ mục được nhóm (còn gọi là bảng) để lấy dữ liệu thực tế. Điều này nghe có vẻ khó hiểu tôi biết nhưng đọc tiếp và tất cả sẽ trở nên rõ ràng.
Vì chỉ mục không được nhóm của chúng tôi chỉ chứa trường Tên khách hàng (các giá trị trường được lập chỉ mục được lưu trữ trong các nút trung gian) và con trỏ tới dữ liệu là ID khách hàng, nên chỉ mục không có bản ghi của Khách hàng. Tên khách hàng phải được tìm nạp từ chỉ mục hoặc bảng được nhóm.
Khi chạy truy vấn này, tôi nhận được kế hoạch thực hiện sau:
Có hai điều quan trọng để bạn chú ý trong ảnh chụp màn hình ở trên
- SQL đang nói rằng tôi có một chỉ mục bị thiếu (văn bản màu xanh lá cây). SQL đang đề nghị tôi tạo một chỉ mục trên Tên khách hàng, bao gồm cả ID khách hàng và Khách hàng.
- Bạn cũng sẽ thấy rằng 99% thời gian của truy vấn được dành cho việc thực hiện tra cứu khóa trên chỉ mục khóa chính / chỉ mục cụm.
Tại sao SQL lại đề xuất chỉ mục trên Tên khách hàng? Chà vì chỉ mục chỉ chứa ID khách hàng và SQL của khách hàng vẫn phải tìm Tên khách hàng từ các chỉ mục bảng / cụm.
Nếu chúng tôi tạo chỉ mục và chúng tôi đã bao gồm cột Khách hàng Tên trong chỉ mục, SQL sẽ có thể đáp ứng toàn bộ truy vấn bằng cách chỉ đọc chỉ mục không được phân cụm. Đây là lý do tại sao SQL đề nghị tôi thay đổi chỉ mục không phân cụm của mình.
Ở đây bạn có thể thấy hoạt động bổ sung mà SQL cần thực hiện để lấy cột CustomerSurname từ khóa được nhóm
Do đó, số lượng các hoạt động như sau:
- Thực hiện tìm kiếm nhị phân trên chỉ mục không phân cụm bằng cách so sánh giá trị được tìm kiếm với các giá trị ở cấp độ trung gian
- Đối với các nút phù hợp, hãy đọc nút cấp độ lá sẽ chứa con trỏ cho dữ liệu trong chỉ mục được nhóm (các nút cấp độ lá sẽ chứa các giá trị khóa chính theo cách này).
- Đối với mỗi giá trị được trả về, hãy đọc chỉ mục được nhóm (bảng) để lấy các giá trị hàng ở đây, chúng tôi sẽ đọc Tên khách hàng.
- Trả về các hàng khớp
Đó là 4 thao tác để lấy các giá trị ra. Hai lần số lượng hoạt động cần thiết so với việc đọc chỉ mục cụm. Điều này cho bạn thấy rằng chỉ mục được nhóm của bạn là chỉ mục mạnh nhất của bạn vì nó chứa tất cả dữ liệu.
Vì vậy, chỉ để làm rõ một điểm cuối cùng. Tại sao tôi nói rằng con trỏ trong chỉ mục không được nhóm là giá trị khóa chính? Vâng để chứng minh rằng các nút cấp độ lá của chỉ mục không được nhóm chứa giá trị khóa chính tôi thay đổi truy vấn của mình thành:
SELECT CustomerID
FROM Customer
WHERE CustomerName='Jane'
Trong truy vấn này, SQL có thể đọc CustomerID từ chỉ mục không được nhóm. Nó không cần phải tìm kiếm trên chỉ mục cụm. Điều này bạn có thể thấy bởi kế hoạch thực hiện trông như thế này.
Lưu ý sự khác biệt giữa truy vấn này và truy vấn trước. Không có tra cứu. SQL có thể tìm thấy tất cả dữ liệu trong chỉ mục không được phân cụm
Hy vọng rằng bạn có thể bắt đầu hiểu rằng chỉ mục được phân cụm là bảng và các chỉ mục không được phân cụm KHÔNG chứa tất cả dữ liệu. Lập chỉ mục sẽ tăng tốc các lựa chọn do thực tế là các tìm kiếm nhị phân có thể được thực hiện nhưng chỉ các chỉ mục được nhóm chứa tất cả dữ liệu. Vì vậy, tìm kiếm trên một chỉ mục không được phân cụm sẽ hầu như luôn luôn dẫn đến các giá trị được tải từ chỉ mục được phân cụm. Các hoạt động bổ sung này làm cho các chỉ mục không được phân cụm kém hiệu quả hơn một chỉ mục được phân cụm.
Hy vọng điều này sẽ làm rõ ràng mọi thứ. Nếu bất cứ điều gì không có ý nghĩa xin vui lòng gửi bình luận và tôi sẽ cố gắng làm rõ. Ở đây khá muộn và não tôi cảm thấy một chút phẳng lặng. Thời gian cho một con bò đỏ.