Lựa chọn chỉ mục cụm - PK hoặc FK?


11

Tôi có một bảng SQL Server 2014 giống như sau:

OrderId     int           not null IDENTITY --this is the primary key column
OrderDate   datetime2     not null
CustomerId  int           not null
Description nvarchar(255) null

Một số người trong nhóm của tôi đã gợi ý rằng chỉ số được nhóm nên được bật OrderId, nhưng tôi nghĩ rằng dấu CustomerId+ OrderIdsẽ là lựa chọn tốt hơn vì những lý do sau:

  • Hầu như tất cả các truy vấn sẽ được tìm kiếm WHERE CustomerId = @param, khôngOrderId
  • CustomerIdlà một khóa ngoại đối với Customerbảng, do đó, có một chỉ mục được nhóm với CustomerIdnên tăng tốc độ tham gia
  • Mặc dù CustomerIdkhông phải là duy nhất, nhưng có thêm OrderIdcột được chỉ định trong chỉ mục sẽ đảm bảo tính duy nhất (Chúng tôi có thể sử dụng UNIQUEtừ khóa khi tạo chỉ mục được nhóm trên 2 cột đó, để tránh chi phí không có tính duy nhất)
  • Khi dữ liệu được chèn, CustomerIdOrderIdkhông bao giờ thay đổi, vì vậy những hàng này sẽ không di chuyển xung quanh sau khi ghi ban đầu.
  • Truy cập dữ liệu xảy ra thông qua ORM yêu cầu tất cả các cột theo mặc định, do đó, khi truy vấn dựa vào CustomerId, chỉ mục được nhóm sẽ có thể cung cấp tất cả các cột mà không cần bất kỳ công việc bổ sung nào.

Liệu CustomerIdOrderIdcách tiếp cận có vẻ như là lựa chọn tốt nhất được đưa ra ở trên? Hoặc, là OrderIdtốt hơn, vì nó là một cột duy nhất đảm bảo tính duy nhất của chính nó?

Hiện tại, bảng có một chỉ mục được nhóm OrderIdvà một chỉ mục CustomerIdkhông được bao gồm, nhưng nó không bao gồm, vì vậy chúng tôi đang sử dụng ORM và tất cả các cột được yêu cầu, nên việc lấy lại chúng là một công việc bổ sung. Vì vậy, với bài đăng này, tôi đang cố gắng xem xét cải thiện hiệu suất với CI tốt hơn.

Hoạt động trên DB của chúng tôi là khoảng 85% đọc và 15% viết.

Câu trả lời:


5

Cộng đồng wiki trả lời :

Tôi nghĩ rằng một khóa chỉ mục được nhóm tổng hợp với CustomerID là cột đầu tiên sẽ tốt nhất vì đó là trong WHEREmệnh đề của gần như tất cả các truy vấn.

Có thể có nhiều phân chia hơn so với khóa tăng (hoặc nhiều khả năng mật độ trang dưới mức tối ưu trong một thời gian nếu bạn quản lý và duy trì hệ số lấp đầy để tránh chia tách 'xấu'). Tuy nhiên, cải thiện hiệu suất tổng thể cho các truy vấn của khách hàng là đáng kể, vì việc tìm kiếm chính được tránh.

OrderID hoặc OrderDate có thể là tốt nhất cho cột thứ hai tùy thuộc vào các truy vấn quan trọng nhất của bạn.

Ví dụ: nếu khách hàng thấy danh sách theo thứ tự thời gian của các đơn hàng gần đây sau khi đăng nhập vào trang web, OrderDate sẽ là tiếp theo, để tối ưu hóa ORDER BY OrderDate DESC.

Nếu bạn chọn OrderID làm chỉ mục được phân cụm, với chỉ mục không được phân cụm trên CustomerID , bạn vẫn sẽ nhận được các phân tách và phân mảnh, chỉ trong chỉ mục không được phân cụm.


3

Nếu bảng này được viết nhiều chuyên sâu (ví dụ: nhiều INSERTcâu lệnh khác đang diễn ra thay vì các SELECTcâu lệnh chống lại nó), tôi sẽ không đồng ý với câu trả lời wiki .

Chọn CustomerID làm cột đầu tiên của khóa cụm tổng hợp sẽ tạo ra rất nhiều phân chia giữa trang . Bạn hy vọng có rất nhiều khách hàng hiện tại và cũng có được nhiều khách hàng mới mọi lúc. Bởi vì khách hàng (hy vọng) đặt nhiều đơn hàng khi doanh nghiệp của bạn tiếp tục phát triển, cách tiếp cận này sẽ thể hiện một số lượng lớn các phân chia giữa trang sẽ giết chết hiệu suất không chỉ trên ghi, mà còn đọc vì các chỉ mục của bạn sẽ bị phân mảnh nặng nề và có khả năng chứa lượng không gian trắng cao hơn (có nghĩa là lãng phí bộ nhớ và bộ nhớ).

Nếu bạn cảm thấy CustomerID phải là cột hàng đầu của chỉ mục cụm tổng hợp, bạn có thể giảm tác động của các phân tách giữa trang bằng cách điều chỉnh FILLFACTORtrên tất cả các chỉ mục cho bảng này. Điều này sẽ làm giảm số lượng phân chia giữa trang bằng cách tăng kích thước của bảng / chỉ mục. Nếu bạn muốn đi theo lộ trình này, tôi khuyên bạn nên thử nghiệm với giá trị 80 và giảm nếu phân tích cho thấy các phân chia giữa trang vẫn đang giết chết hiệu suất.

Đề nghị của tôi là sử dụng OrderId. OrderID đương nhiên phải có tính tuần tự và tạo ra nhiều phân chia trang cuối tốt hơn và được mong đợi với sự tăng trưởng của bảng. Ngoài ra, cách tiếp cận này sẽ chơi tốt hơn với Phân vùng bảng nếu bạn chọn sử dụng cột OrderDate làm khóa phân vùng. Về các truy vấn liên tục sử dụng trường CustomerID, hãy tạo một chỉ mục không bao gồm để xử lý các truy vấn đó. Chỉ số này sẽ cần được xác định một cách chính xác FILLFACTORvì nó sẽ chịu sự phân tách giữa trang mà tôi đã đề cập ở trên, mặc dù những điều này sẽ không tệ về mặt tổng thể trái ngược với nếu sự phân tách xảy ra so với chỉ mục được phân cụm.

Hoạt động trên DB của chúng tôi là khoảng 85% đọc và 15% viết.

CustomerID+ OrderID(và chỉ định một fillfactor để cho phép tăng trưởng mà không cần phân tách) có lẽ tốt hơn nếu đánh giá đó đúng. Chỉ cần chắc chắn rằng đánh giá là chính xác. Kiểm tra thử nghiệm kiểm tra.


1
Lưu ý rằng việc chèn một đơn đặt hàng cho khách hàng cuối cùng (hoặc duy nhất) trên một trang không phải là "phân chia trang giữa". Vì vậy, nếu Đơn hàng trên mỗi khách hàng cao hoặc chiều rộng hàng lớn, thì số lần chèn Đơn hàng ít hơn sẽ yêu cầu "phân chia trang giữa".
David Browne - Microsoft
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.