Được phân cụm và không được phân cụm


98

Kiến thức cấp thấp hơn của tôi về SQL (Server 2008) còn hạn chế và hiện đang được ghép bởi các DBA của chúng tôi. Hãy để tôi giải thích (tôi đã đề cập đến những tuyên bố rõ ràng với hy vọng rằng tôi đúng, nhưng nếu bạn thấy điều gì sai, vui lòng cho tôi biết) tình huống:

Chúng tôi có một cái bàn chứa 'Lệnh của Tòa án' cho mọi người. Khi tôi tạo bảng, (Tên: CourtOrder), tôi đã tạo nó như sau:

CREATE TABLE dbo.CourtOrder
(
  CourtOrderID INT NOT NULL IDENTITY(1,1), (Primary Key)
  PersonId INT NOT NULL,
  + around 20 other fields of different types.
)

Sau đó, tôi áp dụng chỉ mục không phân cụm cho khóa chính (để tăng hiệu quả). Lý do của tôi là nó là một trường duy nhất (khóa chính) và nên được lập chỉ mục, chủ yếu cho mục đích lựa chọn, như chúng ta thườngSelect from table where primary key = ...

Sau đó, tôi đã áp dụng chỉ mục ĐÃ ĐƯỢC ĐIỀU CHỈNH trên PersonId. Lý do là để nhóm các đơn đặt hàng cho một người cụ thể, vì phần lớn công việc là nhận đơn đặt hàng cho một người. Vì thế,select from mytable where personId = ...

Tôi đã được kéo lên về điều này bây giờ. Tôi đã được thông báo rằng chúng ta nên đặt chỉ mục nhóm trên khóa chính và chỉ mục bình thường trên personId. Điều đó dường như rất lạ đối với tôi. Trước hết, tại sao bạn lại đặt một chỉ mục nhóm trên một cột duy nhất? nó là gì? Chắc chắn đó là một sự lãng phí của chỉ mục nhóm? Tôi đã tin rằng một chỉ mục bình thường sẽ được sử dụng trên một cột duy nhất. Ngoài ra, nhóm chỉ mục sẽ có nghĩa là chúng ta không thể nhóm một cột khác (Mỗi một bảng, phải không?).

Lý do khiến tôi bị nói rằng tôi đã mắc sai lầm là họ tin rằng việc đặt một chỉ mục được phân cụm trên PersonId sẽ khiến việc chèn chậm. Đối với tốc độ tăng 5% của một lựa chọn, chúng tôi sẽ nhận được sự suy giảm 95% về tốc độ khi chèn và cập nhật. Điều đó có đúng và hợp lệ không?

Họ nói rằng bởi vì chúng tôi phân cụm personId, SQL Server phải sắp xếp lại dữ liệu khi chúng tôi chèn hoặc thực hiện thay đổi đối với PersonId.

Vì vậy, tôi đã hỏi, tại sao SQL lại có khái niệm CHỈ SỐ ĐƯỢC ĐIỀU CHỈNH, nếu nó quá chậm? Nó có chậm như họ nói không? Tôi nên thiết lập các chỉ mục của mình như thế nào để đạt được hiệu suất tối ưu? Tôi đã nghĩ rằng SELECT được sử dụng nhiều hơn INSERT ... nhưng họ nói rằng chúng tôi đang gặp sự cố khóa trên INSERTS ...

Hy vọng ai đó có thể giúp tôi.


Câu trả lời:


117

Sự khác biệt giữa chỉ mục được phân cụm so với chỉ mục không được phân cụm là chỉ mục được phân cụm xác định thứ tự vật lý của các hàng trong cơ sở dữ liệu . Nói cách khác, việc áp dụng chỉ mục được phân nhóm PersonIdcó nghĩa là các hàng sẽ được sắp xếp vật lý theo PersonIdbảng, cho phép tìm kiếm chỉ mục trên đó đi thẳng đến hàng (chứ không phải là chỉ mục không theo nhóm, điều này sẽ hướng bạn đến hàng vị trí, thêm một bước bổ sung).

Điều đó nói rằng, thật bất thường khi khóa chính không phải là chỉ mục được phân nhóm, nhưng không phải là không có. Vấn đề với kịch bản của bạn thực sự ngược lại với những gì bạn đang giả định: bạn muốn các giá trị duy nhất trong một chỉ mục được phân nhóm, không phải các bản sao. Vì chỉ mục được phân nhóm xác định thứ tự vật lý của hàng, nếu chỉ mục nằm trên cột không phải là duy nhất, thì máy chủ phải thêm giá trị nền cho các hàng có giá trị khóa trùng lặp (trong trường hợp của bạn là bất kỳ hàng nào có cùng PersonId) để giá trị kết hợp (khóa + giá trị nền) là duy nhất.

Điều duy nhất tôi đề xuất là không sử dụng CourtOrderIdcột thay thế (của bạn ) làm khóa chính, mà thay vào đó sử dụng khóa chính ghép của PersonIdvà một số cột hoặc tập hợp các cột nhận dạng duy nhất khác. Tuy nhiên, nếu điều đó là không thể (hoặc không thực tế), thì hãy đặt chỉ mục nhóm vào CourtOrderId.


Cảm ơn Adam. Vì vậy, khi nào thì một chỉ mục được phân cụm sẽ hữu ích? Tôi nghĩ rằng lợi ích của chỉ mục được phân cụm là để nhóm dữ liệu, ví dụ như khi hầu hết các truy vấn nằm trên một PersonID ... vì vậy dữ liệu sẽ được nhóm lại.
Craig

3
không được sắp xếp theo vật lý PersonId. Nó được sắp xếp theo lôgic PersonId, bất kỳ sự khác biệt nào giữa thứ tự lôgic và vật lý là mức độ phân mảnh lôgic.
Martin Smith,

1
@cdotlister Lợi ích của chỉ mục là sắp xếp dữ liệu chứ không phải nhóm nó (ngụ ý dữ liệu trùng lặp trong chỉ mục). Mặc dù sự phân biệt có vẻ như về mặt ngữ nghĩa, nhưng trong trường hợp các chỉ mục được phân cụm thì không. Nếu có thể, chỉ mục được phân cụm phải nằm trên một thứ xác định duy nhất hàng và (lý tưởng) cũng là cột hoặc tập hợp các cột được truy vấn phổ biến nhất. Đây là lý do tại sao nó thường nằm trên khóa chính.
Adam Robinson

1
@CyberSluethOmega: Tôi không biết; câu hỏi của bạn không chứa đủ thông tin để tôi đưa ra quyết định. Tôi có muốn có một chỉ mục được phân nhóm trên một tập hợp các cột trong đó các hàng thường xuyên được thêm vào hoặc bị xóa không phải ở cuối bảng không? Không. Nhưng tôi thực sự không chắc tại sao bạn lại hỏi như vậy hoặc tại sao lại phản đối.
Adam Robinson

1
@CyberSluethOmega: Internet có thể đưa ra những nhận xét mang tính bảo vệ hoặc lạnh lùng khi chúng không có ý định như vậy. Bạn đã tuyên bố rằng tôi đã nói rằng tôi không biết về trường hợp nào tạo chỉ mục nhóm một thứ gì đó khác với khóa chính, trong khi thực tế thì tôi không nói điều đó. Trong thực tế, những gì tôi nói là "đây là bất thường ..., nhưng không phải không nghe", có nghĩa là tôi làm biết trường hợp này được thực hiện.
Adam Robinson,

14

Tôi hoàn toàn không phải là Chuyên gia SQL ... vì vậy hãy coi đây là chế độ xem của nhà phát triển hơn là chế độ xem DBA ..

Việc chèn vào các chỉ mục được nhóm (được sắp xếp theo thứ tự vật lý) không theo thứ tự tuần tự gây ra thêm công việc cho các lần chèn / cập nhật. Ngoài ra, nếu bạn có nhiều lần chèn diễn ra cùng một lúc và tất cả chúng đều xảy ra ở cùng một vị trí, bạn sẽ có tranh chấp. Hiệu suất cụ thể của bạn thay đổi dựa trên dữ liệu của bạn và cách bạn truy cập dữ liệu đó. Nguyên tắc chung là xây dựng chỉ mục nhóm của bạn trên giá trị hẹp duy nhất trong bảng của bạn (thường là PK)

Tôi cho rằng PersonId của bạn sẽ không thay đổi, vì vậy, các bản Cập nhật không có tác dụng ở đây. Nhưng hãy xem xét ảnh chụp nhanh một vài hàng với PersonId là 1 2 3 3 4 5 6 7 8 8

Bây giờ, hãy chèn 20 hàng mới cho PersonId của 3. Đầu tiên, vì đây không phải là khóa duy nhất, máy chủ sẽ thêm một số byte bổ sung vào giá trị của bạn (đằng sau cảnh) để làm cho nó trở nên duy nhất (cũng thêm không gian) và sau đó là vị trí những sẽ cư trú phải được thay đổi. So sánh điều đó với việc chèn một PK tự động tăng dần, trong đó việc chèn diễn ra ở cuối. Giải thích không mang tính kỹ thuật có thể là do điều này: sẽ ít công việc 'xáo trộn lá' hơn phải làm nếu nó tự nhiên tăng giá trị cao hơn ở cuối bảng so với việc làm lại vị trí của các mục hiện có tại vị trí đó trong khi chèn các mục của bạn.

Bây giờ, nếu bạn đang gặp sự cố với Chèn thì có thể bạn đang chèn một loạt các giá trị PersonId giống nhau (hoặc tương tự) cùng một lúc, điều này gây ra công việc bổ sung này ở nhiều nơi khác nhau trong bảng và sự phân mảnh đang giết chết bạn. Nhược điểm của việc chuyển sang PK được nhóm trong trường hợp của bạn, là nếu bạn đang gặp sự cố chèn ngày hôm nay trên PersonIds có giá trị khác nhau trong toàn bộ bảng, nếu bạn chuyển chỉ mục nhóm của mình sang PK và tất cả các lần chèn hiện xảy ra trong một vị trí thì vấn đề của bạn thực sự có thể trở nên tồi tệ hơn do sự tập trung tranh cãi tăng lên. (Mặt khác, nếu các phụ trang của bạn ngày hôm nay không trải đều, nhưng tất cả thường được tập hợp ở các khu vực giống nhau, thì vấn đề của bạn có thể sẽ dễ dàng hơn bằng cách chuyển chỉ mục nhóm của bạn khỏi PersonId sang PK của bạn vì bạn sẽ giảm thiểu phân mảnh.)

Các vấn đề về hiệu suất của bạn nên được phân tích theo tình huống riêng của bạn và chỉ coi những loại câu trả lời này làm hướng dẫn chung. Đặt cược tốt nhất của bạn là dựa vào một DBA có thể xác nhận chính xác vấn đề của bạn nằm ở đâu. Có vẻ như bạn gặp vấn đề về tranh chấp tài nguyên có thể nằm ngoài một sự điều chỉnh chỉ mục đơn giản. Đây có thể là một triệu chứng của một vấn đề lớn hơn nhiều. (Có thể là vấn đề thiết kế ... nếu không thì hạn chế về tài nguyên.)

Dù thế nào đi nữa, chúc may mắn!


5

Một số tác giả làm đề nghị không phải là "lãng phí" sự CItrên một identitycột nếu có một sự thay thế đó sẽ mang lại lợi ích truy vấn nhiều.

Từ Hướng dẫn thiết kế chỉ mục theo cụm MSDN , khóa phải được chọn theo các tiêu chí sau

  1. Có thể được sử dụng cho các truy vấn thường xuyên sử dụng.
  2. Cung cấp một mức độ độc đáo cao.
  3. Có thể được sử dụng trong các truy vấn phạm vi.

CourtOrderIDCột của bạn đáp ứng 2. Cuộc PersonIdgặp gỡ của bạn 13. Vì hầu hết các hàng sẽ kết thúc với uniqueifierdù được thêm vào, bạn cũng có thể chỉ cần khai báo nó là duy nhất và sử dụng PersonId,CourtOrderIDvì nó sẽ có cùng chiều rộng nhưng hữu ích hơn vì khóa chỉ mục nhóm được thêm vào tất cả NCI dưới dạng bộ định vị hàng và điều này sẽ cho phép chúng để bao gồm nhiều truy vấn hơn.

Vấn đề chính khi sử dụng PersonId,CourtOrderIDlàm CI là sự phân mảnh logic có thể sẽ xảy ra sau đó (và điều này đặc biệt ảnh hưởng đến các truy vấn phạm vi mà bạn đang cố gắng trợ giúp) vì vậy bạn sẽ cần theo dõi hệ số lấp đầy, mức độ phân mảnh và thực hiện bảo trì chỉ mục thường xuyên hơn.


3

Nó được giải thích trong liên kết sau: https://msdn.microsoft.com/en-us/ms190457.aspx

Thành cụm

  • Các chỉ mục được phân cụm sắp xếp và lưu trữ các hàng dữ liệu trong bảng hoặc chế độ xem dựa trên các giá trị chính của chúng. Đây là các cột có trong định nghĩa chỉ mục. Chỉ có thể có một chỉ mục nhóm cho mỗi bảng, vì bản thân các hàng dữ liệu chỉ có thể được sắp xếp theo một thứ tự.

  • Thời gian duy nhất các hàng dữ liệu trong bảng được lưu trữ theo thứ tự đã sắp xếp là khi bảng chứa chỉ mục được phân nhóm. Khi một bảng có chỉ mục được phân cụm, bảng đó được gọi là bảng được phân nhóm. Nếu một bảng không có chỉ mục được phân cụm, các hàng dữ liệu của nó được lưu trữ trong một cấu trúc không có thứ tự được gọi là một đống.

Không bao gồm

  • Các chỉ mục không phân tán có cấu trúc tách biệt với các hàng dữ liệu. Chỉ mục không phân biệt c chứa các giá trị khóa của chỉ mục không được phân bổ và mỗi mục nhập giá trị khóa có một con trỏ đến hàng dữ liệu chứa giá trị khóa .

  • Con trỏ từ một hàng chỉ mục trong một chỉ mục không phân biệt đến một hàng dữ liệu được gọi là bộ định vị hàng. Cấu trúc của bộ định vị hàng phụ thuộc vào việc các trang dữ liệu được lưu trữ trong một bảng hay một nhóm. Đối với một đống, một bộ định vị hàng là một con trỏ đến hàng. Đối với bảng được phân nhóm, công cụ định vị hàng là khóa chỉ mục được phân nhóm.

  • Bạn có thể thêm các cột không khóa vào cấp độ lá của chỉ mục không phân biệt để vượt qua giới hạn khóa chỉ mục hiện có, 900 byte và 16 cột khóa, và thực hiện các truy vấn được bao phủ, lập chỉ mục, đầy đủ.


-3

Một số db với một số lựa chọn khó chịu, tham gia vào một thủ tục được lưu trữ - chỉ khác biệt là chỉ mục

INDEXES - nhóm so với không phân nhóm

  891 rows
  10 sec
  NONCLUSTERED 

  OR

  891 rows
  14 sec
  CLUSTERED
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.