Trong khi tạo cơ sở dữ liệu kiểm tra cho một câu hỏi khác mà tôi đã hỏi trước đó, tôi đã nhớ về Khóa chính có thể được khai báo NONCLUSTERED
Khi nào bạn sẽ sử dụng NONCLUSTERED
khóa chính thay vì CLUSTERED
khóa chính?
Cảm ơn trước
Trong khi tạo cơ sở dữ liệu kiểm tra cho một câu hỏi khác mà tôi đã hỏi trước đó, tôi đã nhớ về Khóa chính có thể được khai báo NONCLUSTERED
Khi nào bạn sẽ sử dụng NONCLUSTERED
khóa chính thay vì CLUSTERED
khóa chính?
Cảm ơn trước
Câu trả lời:
Câu hỏi không phải là 'khi nào PK nên là NC', mà thay vào đó bạn nên hỏi 'khóa thích hợp cho chỉ mục được nhóm' là gì?
Và câu trả lời thực sự phụ thuộc vào cách bạn truy vấn dữ liệu . Chỉ mục được nhóm có một lợi thế so với tất cả các chỉ mục khác: vì nó luôn bao gồm tất cả các cột, luôn luôn bao phủ. Do đó, các truy vấn có thể tận dụng chỉ mục được phân cụm chắc chắn không cần sử dụng tra cứu để đáp ứng một số cột và / hoặc các vị từ được chiếu.
Một mảnh khác của câu đố là làm thế nào một chỉ mục có thể được sử dụng ? Có ba mẫu điển hình:
Vì vậy, nếu bạn phân tích tải dự kiến của mình (các truy vấn) và phát hiện ra rằng một số lượng lớn các truy vấn sẽ sử dụng một chỉ mục cụ thể vì chúng sử dụng một mẫu truy cập nhất định có lợi từ một chỉ mục, sẽ hợp lý khi đề xuất chỉ mục đó làm chỉ mục được nhóm.
Tuy nhiên, một yếu tố khác là khóa chỉ mục được phân cụm là khóa tra cứu được sử dụng bởi tất cả các chỉ mục không được phân cụm và do đó, một khóa chỉ mục được phân cụm rộng tạo ra hiệu ứng gợn và mở rộng tất cả các chỉ mục không phân cụm và các chỉ mục rộng có nghĩa là nhiều trang hơn, nhiều I / O hơn , trí nhớ nhiều hơn, lòng tốt ít hơn.
Một chỉ mục cụm tốt là ổn định , nó không thay đổi trong suốt vòng đời của thực thể, bởi vì một thay đổi trong các giá trị khóa chỉ mục được phân cụm có nghĩa là hàng phải được xóa và chèn trở lại.
Và một chỉ mục được nhóm tốt phát triển theo thứ tự không ngẫu nhiên (mỗi giá trị khóa mới được chèn lớn hơn giá trị trước) để tránh phân tách và phân mảnh trang (mà không làm rối tung FILLFACTOR
s).
Vì vậy, bây giờ chúng ta đã biết khóa chỉ mục được nhóm tốt là gì, khóa chính (là thuộc tính logic mô hình hóa dữ liệu) có khớp với các yêu cầu không? Nếu có, thì PK nên được nhóm lại. Nếu không, thì PK không được phân cụm.
Để đưa ra một ví dụ, hãy xem xét một bảng sự kiện bán hàng. Mỗi mục có một ID là khóa chính. Nhưng phần lớn các truy vấn yêu cầu dữ liệu giữa một ngày và một ngày khác, do đó, khóa chỉ mục được nhóm tốt nhất sẽ là ngày bán hàng , không phải ID . Một ví dụ khác về việc có một chỉ mục được nhóm khác với khóa chính là khóa có độ chọn lọc rất thấp, như 'danh mục' hoặc 'trạng thái', một khóa chỉ có rất ít giá trị riêng biệt. Có một khóa chỉ mục được nhóm với khóa chọn thấp này là khóa ngoài cùng bên trái, ví dụ (state, id)
, thường có ý nghĩa vì các phạm vi quét tìm kiếm tất cả các mục trong một 'trạng thái' cụ thể.
Một lưu ý cuối cùng về khả năng của khóa chính không được phân cụm trong một heap (tức là không có chỉ số nào được phân cụm). Đây có thể là một kịch bản hợp lệ, lý do điển hình là khi hiệu suất chèn số lượng lớn là rất quan trọng, vì các đống có thông lượng chèn hàng loạt tốt hơn đáng kể khi so sánh với các chỉ số được nhóm.
(state, id)
. Trong ví dụ này, yêu cầu "chỉ số phân cụm tốt phát triển theo thứ tự không ngẫu nhiên" sẽ không được đáp ứng, phải không? Vì vậy, chúng ta có thể coi nó là chỉ số cụm tốt?
Lý do cơ bản để sử dụng các chỉ mục Clustered được nêu trên Wikipedia :
Phân cụm làm thay đổi khối dữ liệu thành một thứ tự riêng biệt nhất định để khớp với chỉ mục, dẫn đến dữ liệu hàng được lưu trữ theo thứ tự. Do đó, chỉ có thể tạo một chỉ mục cụm trên một bảng cơ sở dữ liệu nhất định. Chỉ số nhóm có thể làm tăng đáng kể tốc độ tổng thể thu hồi, nhưng thường chỉ nơi dữ liệu được truy cập tuần tự trong cùng hoặc đảo ngược thứ tự của các nhóm chỉ số , hoặc khi một loạt các mặt hàng được chọn.
Nói rằng tôi có một bảng Người và những người này có cột Quốc gia và Khóa chính duy nhất. Đó là bảng nhân khẩu học, vì vậy đây là những điều duy nhất tôi quan tâm; Quốc gia nào và có bao nhiêu người độc đáo gắn liền với quốc gia đó.
Do đó, tôi chỉ có khả năng CHỌN Ở ĐÂU hoặc ĐẶT HÀNG theo cột Quốc gia; một chỉ mục được nhóm trên Khóa chính không giúp ích gì cho tôi, tôi không truy cập dữ liệu này bằng PK, tôi đang truy cập nó bằng cột khác. Vì tôi chỉ có thể có một chỉ mục được nhóm trên một bảng, việc khai báo PK của tôi là Clustered sẽ ngăn tôi sử dụng Chỉ mục cụm trên Quốc gia.
Ngoài ra, đây là một bài viết hay về Chỉ mục được phân cụm so với các chỉ mục không bao gồm , hóa ra các chỉ mục được phân cụm gây ra các vấn đề về hiệu năng chèn trong SQL Server 6.5 (ít nhất hy vọng là không phù hợp với hầu hết chúng ta ở đây).
Nếu bạn đặt một chỉ mục được nhóm trên một cột IDENTITY, thì tất cả các lần chèn của bạn sẽ diễn ra trên trang cuối cùng của bảng - và trang đó bị khóa trong thời gian của mỗi IDENTITY. Không có vấn đề gì lớn ... trừ khi bạn có 5000 người mà tất cả đều muốn trang cuối cùng. Sau đó, bạn có rất nhiều tranh cãi cho trang đó
Lưu ý rằng đây không phải là trường hợp trong các phiên bản sau.
Nếu khóa chính của bạn là của UNIQUEIDENTIFIER
, hãy đảm bảo chỉ định nó NONCLUSTERED
. Nếu bạn làm cho nó được nhóm lại, mỗi lần chèn sẽ phải thực hiện một loạt các bản ghi để chèn hàng mới vào đúng vị trí. Điều này sẽ tăng hiệu suất.
UNIQUEIDENTIFIER
kiểu tuần tự cũng tồn tại và có cùng xác suất tạo các khóa duy nhất, mặc dù nó vẫn phải chịu kích thước 128.
Một ví dụ rất phổ biến:
Customer
bảng với CustomerID
nhưCLUSTERED PRIMARY KEY
OrderID (PK), CustomerID, OrderDate
và một số cột khácOrderPositions
với OrderPositionID (PK), OrderId, ProductID, Amount, Price ...
Tất nhiên "nó phụ thuộc" là - gần như luôn luôn - câu trả lời đúng, nhưng hầu hết các ứng dụng (không phải BI-Báo cáo) sẽ hoạt động dựa trên khách hàng (ví dụ: bạn đăng nhập với tư cách là khách hàng 278 vào trang web và nhấp vào "Đơn hàng của tôi" hoặc nhân viên bán hàng liệt kê tất cả các đơn đặt hàng cho khách hàng 4569 hoặc thói quen hóa đơn của bạn sẽ tổng hợp tất cả các đơn đặt hàng cho khách hàng 137).
Trong trường hợp này, sẽ không có nhiều ý nghĩa để phân cụm bảng theo OrderID
. Có, bạn sẽ có các truy vấn SELECT ... WHERE OrderId = ?
để liệt kê chi tiết đơn hàng, nhưng đây thường là chỉ mục ngắn và rẻ (3 lần đọc) tìm kiếm.
Mặt khác, nếu bạn phân cụm Order
bảng của mình theo CustomerID
, nó sẽ không phải thực hiện nhiều lần tra cứu chính mỗi khi bạn truy vấn bảng CustomerId = ?
.
Các CLUSTERED INDEX
nên luôn UNIQUE
, nếu không SQL Server sẽ thêm một vô hình (= không sử dụng được) INT cột UNIQUIFIER
để đảm bảo uniquiness - và nó sẽ có ý nghĩa nhiều hơn nữa để thêm sản (có thể sử dụng) dữ liệu sau đó một số nội dung ngẫu nhiên (tùy thuộc vào thứ tự chèn).
Bởi vì một khách hàng (hy vọng) sẽ đặt nhiều hơn một đơn hàng, chúng tôi sẽ phải thêm OrderID
hoặc (nếu bạn thường sắp xếp cho việc này) OrderDate
(nếu đó là một datetime - nếu không thì khách hàng sẽ bị giới hạn một đơn hàng mỗi ngày) các CLUSTERED INDEX
và kết thúc với:
CREATE UNIQUE CLUSTERED INDEX IX_Orders_UQ on Orders (CustomerID, OrderID)
Các quy tắc tương tự áp dụng cho OrderPositions
bảng. Thông thường hầu hết các truy vấn sẽ liệt kê tất cả các vị trí cho vào thứ tự cụ thể, vì vậy bạn nên tạo ra PK với OrderPositionID
như NONCLUSTERED
và một UNIQUE CLUSTERED INDEX
trên OrderId, OrderPositionID
.
BTW: đúng là Customer
bảng được phân cụm bởi PK của nó ( CustomerID
bởi vì nó là "Bảng cấp cao nhất" và sẽ - trong một ứng dụng thông thường - chủ yếu được truy vấn bởi CustomerID của nó.
Bàn tra cứu tinh khiết như ví dụ Genders
hay InvoiceTypes
hay PaymentType
cũng là một ví dụ về bảng nên được nhóm bởi PK của nó (vì bạn thường sẽ tham gia cùng họ trên GenderId
, InvoiceTypeId
hoặc PaymentTypeId
).
Khi một chỉ số cụm được coi là có lợi cho toàn bộ hệ thống hơn là một cụm PK bằng cách sử dụng một số phép đo hiệu suất. Chỉ có thể có một chỉ mục được nhóm trên một bảng.
Các biện pháp ví dụ về hiệu suất là thời gian truy vấn đơn (tốc độ), tích hợp tổng thời gian truy vấn so với bảng (hiệu quả) và phải thêm nhiều cột bao gồm vào một chỉ mục không phân cụm rất lớn để đạt được hiệu suất tương tự như cụm (kích thước ).
Điều này có thể xảy ra khi dữ liệu thường được truy xuất bằng cách sử dụng một chỉ mục không phải là duy nhất, chứa null (không được phép trong PK) hoặc PK được thêm vào vì lý do thứ cấp (chẳng hạn như sao chép hoặc nhận dạng hồ sơ kiểm toán).