Thông thường, khi chọn khóa chính, bạn cũng chọn khóa theo nhóm. Cả hai thường bị nhầm lẫn, nhưng bạn phải hiểu sự khác biệt.
Khóa chính là hợp lý kinh doanh các yếu tố. Khóa chính được ứng dụng của bạn sử dụng để xác định một thực thể và cuộc thảo luận về khóa chính chủ yếu là sử dụng khóa tự nhiên hoặc khóa thay thế. Các liên kết đi vào chi tiết hơn, nhưng ý tưởng cơ bản là các khóa tự nhiên có nguồn gốc từ một thuộc tính thực thể hiện có như ssn
hoặc phone number
, trong khi các khóa thay thế không có ý nghĩa gì đối với thực thể doanh nghiệp, chẳng hạn như id
hoặc rowid
và chúng thường thuộc loại IDENTITY
hoặc một số loại uuid. Ý kiến cá nhân của tôi là khóa thay thế ưu việt hơn khóa tự nhiên và sự lựa chọn phải luôn là giá trị nhận dạng cho các ứng dụng chỉ cục bộ, guids cho bất kỳ loại dữ liệu phân tán nào. Khóa chính không bao giờ thay đổi trong suốt thời gian tồn tại của thực thể.
Khóa được nhóm là khóa xác định lưu trữ vật lý của các hàng trong bảng. Hầu hết các lần chúng trùng lặp với khóa chính (mã định danh thực thể logic), nhưng điều đó thực sự không được thực thi cũng như không bắt buộc. Khi cả hai khác nhau, điều đó có nghĩa là có một chỉ mục duy nhất không phân cụm trên bảng thực hiện khóa chính. Các giá trị khóa được phân cụm thực tế có thể thay đổi trong suốt thời gian tồn tại của hàng, dẫn đến việc hàng được di chuyển vật lý trong bảng đến một vị trí mới. Nếu bạn phải tách khóa chính khỏi khóa được phân cụm (và đôi khi bạn làm vậy), việc chọn một khóa được phân cụm tốt sẽ khó hơn đáng kể so với việc chọn một khóa chính. Có hai yếu tố chính thúc đẩy thiết kế khóa theo nhóm của bạn:
- Kiểu truy cập dữ liệu phổ biến .
- Cân nhắc về bộ nhớ .
Dạng truy cập dữ liệu . Bằng cách này, tôi hiểu cách bảng được truy vấn và cập nhật. Hãy nhớ rằng các khóa được phân cụm xác định thứ tự thực tế của các hàng trong bảng. Đối với một số mẫu truy cập nhất định, một số bố cục tạo ra tất cả sự khác biệt trên thế giới về tốc độ truy vấn hoặc cập nhật tính đồng bộ:
-
dữ liệu lưu trữ hiện tại so với. Trong nhiều ứng dụng, dữ liệu của tháng hiện tại thường xuyên được truy cập, trong khi dữ liệu trong quá khứ hiếm khi được truy cập. Trong những trường hợp như vậy, thiết kế bảng sử dụng phân vùng bảng theo ngày giao dịch, thường sử dụng thuật toán cửa sổ trượt. Phân vùng tháng hiện tại được giữ trên nhóm tệp nằm trên đĩa nhanh nóng, dữ liệu cũ đã lưu trữ được chuyển sang nhóm tệp được lưu trữ trên bộ lưu trữ rẻ hơn nhưng chậm hơn. Rõ ràng trong trường hợp này, khóa cụm (ngày) không phải là khóa chính (id giao dịch). Sự tách biệt của cả hai được thúc đẩy bởi các yêu cầu về tỷ lệ, vì trình tối ưu hóa truy vấn sẽ có thể phát hiện ra rằng các truy vấn chỉ quan tâm đến phân vùng hiện tại và thậm chí không xem xét các truy vấn lịch sử.
-
Xử lý kiểu hàng đợi FIFO. Trong trường hợp này, bảng có hai điểm nóng:phần đuôi nơi xảy ra chèn (enqueue) và đầu nơi xảy ra xóa (dequeue). Khóa phân cụm phải tính đến điều này và tổ chức bảng sao cho tách biệt vật lý vị trí đuôi và đầu trên đĩa, để cho phép sự đồng nhất giữa enqueue và dequeue, ví dụ. bằng cách sử dụng một khóa thứ tự hàng đợi. Trong tinh khiết xếp hàng đợi khóa nhóm này là khóa duy nhất, vì không có khóa chính trên bảng (nó chứa thông báo , không phải thực thể ). Nhưng hầu hết các trường hợp hàng đợi không thuần túy, nó cũng đóng vai trò là nơi lưu trữ các thực thể và dòng giữa hàng đợi và bảng bị chảy máu. Trong trường hợp này cũng có một khóa chính, không thể là khóa nhóm:các thực thể có thể được xếp lại hàng, do đó thay đổi giá trị khóa được nhóm theo thứ tự xếp hàng, nhưng chúng không thể thay đổi giá trị khóa chính. Việc không nhìn thấy sự phân tách là lý do chính khiến các hàng đợi được hỗ trợ bởi bảng của người dùng nổi tiếng là rất khó để đi đúng và có nhiều bế tắc:bởi vì hàng đợi và hàng đợi xảy ra xen kẽ trong bảng, thay vì cục bộ ở phần đuôi và phần đầu của hàng đợi.
-
Xử lý tương quan. Khi ứng dụng được thiết kế tốt, nó sẽ phân vùng xử lý các mục tương quan giữa các luồng công nhân của nó. Ví dụ:một bộ xử lý được thiết kế để có 8 luồng công nhân (giả sử để khớp với 8 CPU trên máy chủ) vì vậy các bộ xử lý phân vùng dữ liệu giữa chúng với nhau, ví dụ. worker 1 chỉ chọn các tài khoản có tên A đến E, worker 2 F đến J, v.v. Trong những trường hợp như vậy, bảng thực sự nên được nhóm theo tên tài khoản (hoặc bằng một khóa tổng hợp có vị trí ngoài cùng bên trái là chữ cái đầu tiên của tên tài khoản), để nhân viên bản địa hóa các truy vấn và cập nhật của họ trong bảng. Một bảng như vậy sẽ có 8 điểm nóng riêng biệt, xung quanh khu vực tập trung mỗi công nhân vào lúc này, nhưng điều quan trọng là chúng không chồng lên nhau (không chặn). Kiểu thiết kế này phổ biến trên các thiết kế OLTP thông lượng cao và trong tải chuẩn TPCC, trong đó kiểu phân vùng này cũng phản ánh trong vị trí bộ nhớ của các trang được tải trong vùng đệm (địa phương NUMA), nhưng tôi lạc đề.
Cân nhắc về Lưu trữ . Khóa được nhóm chiều rộng có các phép lặp lại rất lớn trong bộ nhớ của bảng. Đối với một phím, khóa chiếm không gian trong mỗi trang không phải của cây b-tree, vì vậy, một khóa lớn sẽ chiếm nhiều không gian hơn. Thứ hai, và thường quan trọng hơn, là khóa được phân cụm được sử dụng làm khóa tra cứu bởi mọi khóa không phân cụm, vì vậy mọi khóa không được phân cụm sẽ phải lưu trữ toàn bộ chiều rộng của khóa được phân cụm cho mỗi hàng. Đây là điều làm cho các khóa cụm lớn như varchar (256) và các khóa có nhiều lựa chọn không tốt cho các khóa chỉ mục được phân cụm.
Ngoài ra, việc lựa chọn khóa có tác động đến sự phân mảnh chỉ mục theo cụm, đôi khi ảnh hưởng đáng kể đến hiệu suất.
Hai lực lượng này đôi khi có thể đối nghịch nhau, kiểu truy cập dữ liệu yêu cầu một khóa cụm lớn nhất định sẽ gây ra các vấn đề về lưu trữ. Trong những trường hợp như vậy tất nhiên cần có sự cân bằng, nhưng không có công thức kỳ diệu nào. Bạn đo lường và bạn kiểm tra để đạt được điểm tốt.
Vậy chúng ta kiếm được gì từ tất cả những thứ này? Luôn bắt đầu với việc xem xét khóa được phân nhóm cũng là khóa chính của biểu mẫu entity_id IDENTITY(1,1) NOT NULL
. Tách hai và sắp xếp bảng cho phù hợp (ví dụ:phân vùng theo ngày) khi hết hạn.