Thứ tự trường theo thứ tự chỉ mục tổng hợp với các trường có độ chọn lọc cao và độ chọn lọc thấp


11

Tôi có một bảng SQL Server với hơn 3 tỷ hàng. Một trong những truy vấn của tôi mất một thời gian rất dài vì vậy tôi đang xem xét tối ưu hóa nó. Truy vấn trông như thế này:

SELECT [Enroll_Date]
      ,Count(*) AS [Record #]
      ,Count(Distinct UserID) AS [User #]
  FROM UserTable
  GROUP BY [Enroll_Date]

[Enroll_Date] là cột có độ chọn lọc thấp với ít hơn 50 giá trị có thể, trong khi cột UserID là cột có độ chọn lọc cao với hơn 200 triệu giá trị riêng biệt. Dựa trên nghiên cứu của tôi, tôi tin rằng tôi nên tạo một chỉ số tổng hợp không phân cụm trên hai cột này và theo lý thuyết, cột có tính chọn lọc cao phải là cột đầu tiên. Nhưng tôi không chắc chắn trong trường hợp của mình, điều đó có hiệu quả không vì tôi đang sử dụng cột có độ chọn lọc thấp trong nhóm theo mệnh đề.

Bảng này không có chỉ số cụm.


Bạn có thể đăng kế hoạch thực hiện xml thực tế (sử dụng pastebin và liên kết nó ở đây)? Phiên bản nào của máy chủ sql bạn đang sử dụng?
Kin Shah

3
Các chỉ mục với cột có tính chọn lọc cao trước tiên sẽ vô dụng đối với truy vấn cụ thể.
ypercubeᵀᴹ 17/2/2016

Đó là cách tốt nhất để sử dụng cột có độ chọn lọc cao hơn làm cột khóa đầu tiên trong một chỉ mục (thông thường). Trong kịch bản này, như bạn đoán, nó hoàn toàn không giúp bạn. Bạn có thể cần hai chỉ số! Điều gì xảy ra khi bạn sử dụng notify_date trước và user_id thứ hai?
paulbarbin 17/2/2016

Câu trả lời:


12

Thay thế cho giải pháp của @ AaronBertrand (nếu bạn không thể hoặc không muốn tạo chế độ xem được lập chỉ mục), tôi sẽ khuyên bạn nên tạo một chỉ mục trên (Enroll_Date, UserID). Nếu loại câu hỏi này rất phổ biến trên bảng của bạn, thì đây thậm chí có thể là chỉ mục được nhóm của bạn.

Nói chung, tôi sẽ không đề xuất các chỉ mục có tính chọn lọc cao như là một "thực tiễn tốt nhất" chung, mà là xem xét chỉ mục nào sẽ cung cấp cho truy vấn của bạn hiệu suất tốt nhất.

Một chỉ mục trên (Enroll_Date, UserID)sẽ cung cấp cho truy vấn của bạn một kế hoạch truy vấn không bị chặn, được tối ưu hóa cao với Luồng tổng hợp.

Luồng kế hoạch truy vấn tổng hợp

"Không chặn" trong ngữ cảnh này có nghĩa là truy vấn không cần đệm bất kỳ lượng dữ liệu đáng kể nào (ví dụ như tổng hợp sắp xếp hoặc băm sẽ), có nghĩa là (a) bắt đầu trả về hàng ngay lập tức và ( b) tiêu thụ thực tế không có bộ nhớ làm việc.


Hài hước, cách nhau 4 giây và cùng một câu trả lời.
usr

11

Aarons trả lời là một giải pháp tuyệt vời. Tôi sẽ trả lời câu hỏi giả sử bạn không muốn thực hiện phương pháp đó.

Truy vấn mà bạn đã đăng thường sẽ được thực hiện bằng cách nhóm trước (Enroll_Date, UserID), sau đó lại tiếp tục (Enroll_Date). Tối ưu hóa này là mới đối với SQL Server 2012. Nó có hiệu lực trong trường hợp một COUNT DISTINCT.

Một chỉ mục trên hai cột theo thứ tự cụ thể (Enroll_Date, UserID)sẽ đủ để có được một kế hoạch hiệu quả, phễu quét một chỉ mục thành hai Tập hợp luồng liên tiếp. Thứ tự ngược lại sẽ không cho phép kế hoạch đó.

Do đó, sử dụng thứ tự (Enroll_Date, UserID). Bạn không có sự lựa chọn ở đây.


Cách nhau 5 giây và cùng một giải pháp. Chơi tốt, thưa ngài. :)
Daniel Hutmacher

@DanielHutmacher OMG, chúng tôi sẽ quản lý gần như khớp với bài đăng của mình lần thứ 3?! +1 cho bạn! Làm thế nào tôi không thể đưa ra một câu trả lời giống hệt nhau?
usr

Trục trặc trong Ma trận. :)
Daniel Hutmacher

Cảm ơn rât nhiều. Tôi đang tạo chỉ mục và sẽ đăng bài cải tiến sau khi hoàn thành. Phiên bản máy chủ là Microsoft SQL Server 2008 R2 trên AWS, nhưng tôi đoán nó vẫn là phiên bản duy nhất bất kể.
Thinkinger

@Thinkinger trong trường hợp bạn không chấp nhận cách tiếp cận của Aarons, bạn có một lựa chọn khó khăn :)
usr

11

Âm thanh giống như một kịch bản lý tưởng cho chế độ xem được lập chỉ mục, cho phép bạn trả tiền cho các tính toán và tổng hợp tại thời điểm viết thay vì thời gian truy vấn.

CREATE VIEW dbo.MyIndexedView
WITH SCHEMABINDING
AS 
  SELECT Enroll_Date, UserID, RawCount = COUNT_BIG(*)
  FROM dbo.UserTable
  GROUP BY Enroll_Date, UserID;
GO

CREATE UNIQUE CLUSTERED INDEX CIX_miv ON dbo.MyIndexedView(Enroll_Date, UserID);

Điều đó sẽ mất một chút thời gian để tạo và tất nhiên sẽ yêu cầu bảo trì trong tất cả các hoạt động DML, giống như một chỉ mục trên bảng cơ sở.

Bây giờ truy vấn đối với chế độ xem này sẽ khá giống nhau - mỗi hàng trong chế độ xem hiện đại diện cho một kết hợp người dùng / ngày riêng biệt, do đó, con số đó có thể được tính bằng một COUNT (*), trong khi tổng số hàng trong bảng cơ sở là đã được tổng hợp một phần cho bạn, bây giờ bạn chỉ cần thêm chúng bằng SUM mỗi ngày:

SELECT Enroll_Date, 
  [Record #] = SUM(RawCount),
  [User #] = COUNT(*)
FROM dbo.MyIndexedView WITH (NOEXPAND)
GROUP BY Enroll_Date; 

Đã thêm gợi ý NOEXPAND, sau khi nhớ cái nàycái này .

Tôi có thể chắc chắn nói với bạn rằng truy vấn này sẽ nhanh hơn truy vấn hiện tại của bạn (nhưng không phải là bao nhiêu), ngoại trừ trong trường hợp hiếm hoi mà bạn có chính xác một người dùng cho mỗi ngày (trong trường hợp đó, cùng một lượng dữ liệu sẽ có được đọc) và các cột mà chúng ta biết là các cột duy nhất trong chỉ mục của bảng cơ sở. Việc tăng hiệu suất trong thời gian đọc có xứng đáng với công việc làm thêm sẽ ảnh hưởng đến phần ghi của khối lượng công việc của bạn hay không là điều chúng tôi không thể nói với bạn - bạn sẽ phải kiểm tra nó để đo lường sự đánh đổi (không có chỉ số nào là miễn phí).

Và nếu bạn thường xuyên sử dụng các mệnh đề WHERE phổ biến tương tự với Enroll_Date cho các phạm vi được xác định rõ ràng (cụ thể là quý hoặc năm hiện tại), bạn có thể thêm các chỉ mục được lọc phù hợp làm giảm thêm I / O đó (nhưng luôn luôn có một đánh đổi).

Bạn cũng có thể xem xét đặt một chỉ mục cụm trên bảng cơ sở. Đây dường như không phải là một trong những trường hợp sử dụng rất hiếm được hưởng lợi từ một đống.


Tôi vừa xác nhận với IT của chúng tôi và dường như tôi không thể tạo ra loại quan điểm này. Nhưng vẫn đánh giá cao lời khuyên của bạn, và nó sẽ giúp những người khác có thể sử dụng nó.
Thinkinger

1
CNTT của bạn có nghĩ rằng có một sự khác biệt đáng kể giữa chế độ xem được lập chỉ mục và các chỉ mục bổ sung hoặc khác nhau trên bảng cơ sở không? Không hiếu chiến, chỉ tò mò, bởi vì rất nhiều người có quan niệm sai lầm về quan điểm được lập chỉ mục. Tôi thích nghĩ về chúng như một chỉ số cụm, da mỏng hơn trên bàn, nhưng với ít hàng hơn.
Aaron Bertrand

@Thinkinger cũng vậy, lượt xem được lập chỉ mục không chỉ dành cho EE. Kết hợp chế độ xem được lập chỉ mục là chỉ EE. Bạn có thể nhắm mục tiêu trực tiếp chúng bằng cách sử dụng NOEXPAND.
usr
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.