Database
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Database

Cách các chỉ mục được lọc có thể trở thành một tính năng mạnh mẽ hơn

Đừng hiểu sai ý tôi; Tôi thích các chỉ mục được lọc. Chúng tạo cơ hội để sử dụng I / O hiệu quả hơn nhiều và cuối cùng cho phép chúng tôi triển khai các ràng buộc duy nhất tuân thủ ANSI thích hợp (trong đó nhiều hơn một NULL được phép). Tuy nhiên, chúng còn lâu mới hoàn hảo. Tôi muốn chỉ ra một số lĩnh vực mà các chỉ mục đã lọc có thể được cải thiện và làm cho chúng hữu ích và thiết thực hơn nhiều đối với một phần lớn khối lượng công việc ở đó.

Đầu tiên, tin tốt

Các chỉ mục được lọc có thể thực hiện rất nhanh các truy vấn đắt tiền trước đây và làm như vậy sử dụng ít dung lượng hơn (và do đó giảm I / O, ngay cả khi được quét).

Một ví dụ nhanh bằng cách sử dụng Sales.SalesOrderDetailEnlarged (được xây dựng bằng tập lệnh này bởi Jonathan Kehayias (@SQLPoolBoy)). Bảng này có các hàng 4,8MM, với 587 MB dữ liệu và 363 MB chỉ mục. Chỉ có một cột có thể nullable, CarrierTrackingNumber , vì vậy hãy chơi với cái đó. Hiện tại, bảng có khoảng một nửa các giá trị này (2,4MM) là NULL. Tôi sẽ giảm con số đó xuống khoảng 240K để mô phỏng một kịch bản trong đó một tỷ lệ phần trăm nhỏ các hàng trong bảng thực sự đủ điều kiện cho một chỉ mục, để làm nổi bật nhất những lợi ích của một chỉ mục đã lọc. Truy vấn sau ảnh hưởng đến các hàng 2,17MM, để lại 241.507 hàng có giá trị NULL cho CarrierTrackingNumber :

UPDATE Sales.SalesOrderDetailEnlarged 
    SET CarrierTrackingNumber = 'x'
      WHERE CarrierTrackingNumber IS NULL
      AND SalesOrderID % 10 <> 3;

Bây giờ, giả sử có một yêu cầu kinh doanh mà chúng tôi liên tục muốn xem xét các đơn đặt hàng có sản phẩm chưa được chỉ định số theo dõi (hãy nghĩ rằng các đơn đặt hàng được chia nhỏ và vận chuyển riêng). Trên bảng hiện tại, chúng tôi sẽ chạy các truy vấn này (và tôi đã thêm các lệnh DBCC để đảm bảo bộ đệm lạnh trong mọi trường hợp):

DBCC DROPCLEANBUFFERS;
DBCC FREEPROCCACHE;
 
SELECT COUNT(*)
  FROM Sales.SalesOrderDetailEnlarged 
  WHERE CarrierTrackingNumber IS NULL;
 
SELECT ProductID, SalesOrderID
  FROM Sales.SalesOrderDetailEnlarged
  WHERE CarrierTrackingNumber IS NULL;

Yêu cầu quét chỉ mục theo cụm và mang lại các số liệu thời gian chạy sau (như được ghi lại bằng SQL Sentry Plan Explorer):

Ngày xưa (có nghĩa là kể từ SQL Server 2005), chúng tôi đã tạo chỉ mục này (và trên thực tế, ngay cả trong SQL Server 2012, đây là chỉ mục mà SQL Server khuyến nghị):

CREATE INDEX IX_NotVeryHelpful
ON [Sales].[SalesOrderDetailEnlarged] ([CarrierTrackingNumber])
INCLUDE ([SalesOrderID],[ProductID]);

Với chỉ mục đó tại chỗ và chạy lại các truy vấn ở trên, đây là các số liệu, với cả hai truy vấn sử dụng tìm kiếm chỉ mục như bạn có thể mong đợi:

Và sau đó bỏ chỉ mục đó và tạo một chỉ mục hơi khác, chỉ cần thêm WHERE mệnh đề:

CREATE INDEX IX_Filtered_CTNisNULL
ON [Sales].[SalesOrderDetailEnlarged] ([CarrierTrackingNumber])
INCLUDE ([SalesOrderID],[ProductID])
WHERE CarrierTrackingNumber IS NULL;

Chúng tôi nhận được những kết quả này và cả hai truy vấn đều sử dụng chỉ mục đã lọc cho các tìm kiếm của chúng:

Đây là không gian bổ sung theo yêu cầu của mỗi chỉ mục, so với việc giảm thời gian chạy và I / O của các truy vấn trên:

Chỉ mục Không gian chỉ mục Thêm không gian Thời lượng Lượt đọc
Không có chỉ mục riêng 363 MB 15.700 mili giây ~ 164.000
Chỉ mục không được lọc 530 MB 167 MB (+ 46%) 169ms 1,084
Chỉ mục được lọc 367 MB 4 MB (+ 1%) 170ms 1,084


Vì vậy, như bạn có thể thấy, chỉ mục được lọc mang lại những cải tiến về hiệu suất gần như giống với chỉ mục không được lọc (vì cả hai đều có thể lấy dữ liệu của mình bằng cách sử dụng cùng một số lần đọc), nhưng ở mức lưu trữ thấp hơn nhiều chi phí, vì chỉ mục được lọc chỉ phải lưu trữ và duy trì các hàng phù hợp với vị từ bộ lọc.

Bây giờ, hãy đặt bảng trở lại trạng thái ban đầu:

UPDATE Sales.SalesOrderDetailEnlarged
  SET CarrierTrackingNumber = NULL
  WHERE CarrierTrackingNumber = 'x';
 
DROP INDEX IX_NotVeryHelpful ON Sales.SalesOrderDetailEnlarged;
DROP INDEX IX_Filtered_CTNisNULL ON Sales.SalesOrderDetailEnlarged;

Tim Chapman (@chapmandew) và Michelle Ufford (@sqlfool) đã thực hiện một công việc tuyệt vời khi phác thảo những lợi ích về hiệu suất của các chỉ mục được lọc theo cách riêng của họ và bạn cũng nên xem các bài đăng của họ:

  • Michelle Ufford:Các chỉ mục đã lọc:Điều bạn cần biết
  • Tim Chapman:Niềm vui của các chỉ mục được lọc

Ngoài ra, các ràng buộc duy nhất tuân thủ ANSI (loại)

Tôi nghĩ rằng tôi cũng sẽ đề cập ngắn gọn đến các ràng buộc duy nhất tuân thủ ANSI. Trong SQL Server 2005, chúng tôi sẽ tạo một ràng buộc duy nhất như sau:

CREATE TABLE dbo.Personnel
(
  EmployeeID INT PRIMARY KEY,
  SSN CHAR(9) NULL,
  -- ... other columns ...
  CONSTRAINT UQ_SSN UNIQUE(SSN)
);

(Chúng tôi cũng có thể tạo một chỉ mục không phân cụm duy nhất thay vì một ràng buộc; việc triển khai cơ bản về cơ bản là giống nhau.)

Bây giờ, điều này không có vấn đề gì nếu SSN được biết tại thời điểm nhập:

INSERT dbo.Personnel(EmployeeID, SSN)
VALUES(1,'111111111'),(2,'111111112');

Cũng không sao nếu chúng tôi thỉnh thoảng có SSN không được biết vào thời điểm nhập cảnh (hãy nghĩ rằng một người xin Visa hoặc thậm chí có thể là một người lao động nước ngoài không có SSN và sẽ không bao giờ có):

INSERT dbo.Personnel(EmployeeID, SSN)
VALUES(3,NULL);

Càng xa càng tốt. Nhưng điều gì sẽ xảy ra khi chúng ta có một giây nhân viên có SSN không xác định?

INSERT dbo.Personnel(EmployeeID, SSN)
VALUES(4,NULL);

Kết quả:

Msg 2627, Mức 14, Trạng thái 1, Dòng 1
Vi phạm ràng buộc KEY DUY NHẤT 'UQ_SSN'. Không thể chèn khóa trùng lặp trong đối tượng 'dbo.Personnel'. Giá trị khóa trùng lặp là ().
Câu lệnh đã bị kết thúc.

Vì vậy, tại bất kỳ thời điểm nào, chỉ có một giá trị NULL có thể tồn tại trong cột này. Không giống như hầu hết các tình huống, đây là một trường hợp SQL Server coi hai giá trị NULL là bằng nhau (thay vì xác định rằng bằng nhau chỉ đơn giản là không xác định và ngược lại là sai). Nhiều người đã phàn nàn về sự không nhất quán này trong nhiều năm.

Nếu đây là một yêu cầu, bây giờ chúng tôi có thể giải quyết vấn đề này bằng cách sử dụng các chỉ mục đã lọc:

ALTER TABLE dbo.Personnel DROP CONSTRAINT UQ_SSN;
GO
 
CREATE UNIQUE INDEX UQ_SSN ON dbo.Personnel(SSN)
  WHERE SSN IS NOT NULL;

Bây giờ chèn thứ 4 của chúng tôi hoạt động tốt, vì tính duy nhất chỉ được thực thi trên các giá trị không phải NULL. Đây là một kiểu gian lận, nhưng nó đáp ứng các yêu cầu cơ bản mà tiêu chuẩn ANSI dự định (mặc dù SQL Server không cho phép chúng tôi sử dụng ALTER TABLE ... ADD CONSTRAINT cú pháp để tạo một ràng buộc duy nhất đã lọc).

Nhưng, hãy giữ điện thoại

Đây là những ví dụ tuyệt vời về những gì chúng tôi có thể làm với các chỉ mục đã lọc, nhưng có rất nhiều điều chúng tôi vẫn chưa thể làm và kết quả là một số hạn chế và vấn đề phát sinh.

Cập nhật thống kê

Đây là một trong những hạn chế quan trọng hơn IMHO. Các chỉ mục đã lọc không được hưởng lợi từ việc tự động cập nhật thống kê dựa trên phần trăm thay đổi của tập hợp con của bảng được xác định bởi vị từ bộ lọc; nó dựa trên (giống như tất cả các chỉ mục không được lọc) trên toàn bộ bảng. Điều này có nghĩa là, tùy thuộc vào tỷ lệ phần trăm của bảng trong chỉ mục được lọc, số hàng trong chỉ mục có thể tăng gấp bốn lần hoặc giảm một nửa và thống kê sẽ không cập nhật trừ khi bạn làm như vậy theo cách thủ công. Kimberly Tripp đã đưa ra một số thông tin tuyệt vời về điều này (và Gail Shaw trích dẫn một ví dụ trong đó phải mất 257.000 bản cập nhật trước khi số liệu thống kê được cập nhật cho một chỉ mục được lọc chỉ chứa 10.000 hàng):

http://www.sqlskills.com/blogs/kimberly/filtered-indexes-and-filtered-stats-might-become-serious-out-of-date/
http://www.sqlskills.com/ blog / kimberly / category / filter-indexes /

Ngoài ra, đồng nghiệp của Kimberly, Joe Sack (@JosephSack), đã gửi một mục Kết nối đề xuất sửa hành vi này cho cả chỉ mục được lọc và thống kê đã lọc.

Giới hạn biểu thức lọc

Có một số cấu trúc bạn không thể sử dụng trong một vị từ bộ lọc, chẳng hạn như NOT IN , OR và các vị từ động / không xác định như WHERE col >= DATEADD(DAY, -1, GETDATE()) . Ngoài ra, trình tối ưu hóa có thể không nhận ra chỉ mục đã lọc nếu vị từ không khớp chính xác với WHERE mệnh đề trong định nghĩa chỉ mục. Dưới đây là một số mục Connect cố gắng thu hút một số hỗ trợ để có phạm vi phủ sóng tốt hơn tại đây:

Chỉ mục được lọc không cho phép các bộ lọc khi ngừng hoạt động (đóng:theo thiết kế)
Không thể tạo chỉ mục đã lọc với mệnh đề NOT IN (đóng:theo thiết kế)
Hỗ trợ mệnh đề WHERE phức tạp hơn trong các chỉ mục được lọc (hoạt động)

Các mục đích sử dụng tiềm năng khác hiện không thể thực hiện được

Chúng tôi hiện không thể tạo chỉ mục được lọc trên một cột được tính toán liên tục, ngay cả khi nó là xác định. Chúng tôi không thể trỏ khóa ngoại vào một chỉ mục được lọc duy nhất; nếu chúng ta muốn một chỉ mục hỗ trợ khóa ngoại ngoài các truy vấn được hỗ trợ bởi chỉ mục được lọc, chúng ta phải tạo một chỉ mục thứ hai, dư thừa, không được lọc. Và đây là một vài hạn chế tương tự khác đã được bỏ qua hoặc chưa được xem xét:

Có thể tạo chỉ mục được lọc trên cột được tính toán xác định liên tục (hoạt động)
Cho phép chỉ mục duy nhất được lọc làm khóa ứng viên cho khóa ngoại (hoạt động)
khả năng tạo chỉ mục bộ lọc trên các chế độ xem được lập chỉ mục (đã đóng:sẽ không sửa được)
Lỗi phân vùng 1908 - Tăng cường phân vùng (đã đóng:sẽ không sửa được)
TẠO CHỈ SỐ "ĐÃ LỌC" COLUMNSTORE (hoạt động)

Vấn đề với MERGE

MERGE xuất hiện thêm một lần nữa trong danh sách "đề phòng" của tôi:

MERGE đánh giá chỉ mục được lọc trên mỗi hàng, không phải hoạt động đăng, điều này gây ra vi phạm chỉ mục đã lọc (đã đóng:sẽ không sửa được)
MERGE không cập nhật được với chỉ mục được lọc tại chỗ (đóng:cố định)
Lỗi câu lệnh MERGE khi INSERT / DELETE được sử dụng và lọc chỉ mục (hoạt động)
MERGE báo cáo không chính xác các vi phạm chính duy nhất (hoạt động)


Mặc dù một trong những lỗi này (có vẻ liên quan mật thiết) nói rằng nó đã được sửa trong SQL Server 2012, bạn có thể cần liên hệ với PSS nếu bạn gặp phải bất kỳ biến thể nào của vấn đề này, đặc biệt là trên các phiên bản trước đó (hoặc ngừng sử dụng MERGE , như tôi đã đề xuất trước đây).

Giới hạn của công cụ / DMV / tích hợp sẵn

Có nhiều DMV, lệnh DBCC, thủ tục hệ thống và công cụ máy khách mà chúng ta bắt đầu dựa vào theo thời gian. Tuy nhiên, không phải tất cả những thứ này đều được cập nhật để tận dụng các tính năng mới; các chỉ mục được lọc cũng không ngoại lệ. Các mục Connect sau đây chỉ ra một số vấn đề có thể khiến bạn gặp khó khăn nếu bạn muốn chúng hoạt động với các chỉ mục đã lọc:

Không có cách nào tạo chỉ mục đã lọc từ SSMS trong khi thiết kế bảng mới (đã đóng:sẽ không sửa được)
Biểu thức bộ lọc của một chỉ mục được lọc bị mất khi một bảng được Trình thiết kế bảng sửa đổi (đã đóng:sẽ không sửa được)
Trình thiết kế bảng không tập lệnh mệnh đề WHERE trong các chỉ mục đã lọc (hoạt động)
Trình thiết kế bảng SSMS không bảo toàn biểu thức bộ lọc chỉ mục khi xây dựng lại bảng (đã đóng:sẽ không sửa được)
DBCC PAGE đầu ra không chính xác với các chỉ mục đã lọc (hoạt động)
Đề xuất chỉ mục được lọc trong SQL 2008 từ Chế độ xem DM và DTA (đã đóng:sẽ không sửa được)
Các cải tiến đối với các chỉ mục còn thiếu DMV dành cho các chỉ mục được lọc (đã đóng:sẽ không sửa được)
Lỗi cú pháp khi sao chép các chỉ mục đã lọc được nén (đã đóng:sẽ không sửa được)
Tác nhân:các công việc sử dụng các tùy chọn không phải mặc định khi chạy tập lệnh T-SQL (đã đóng:sẽ không sửa được)
Chế độ xem phụ thuộc không thành công với lỗi Transact-SQL 515 (hoạt động)
Chế độ xem phụ thuộc không thành công trên các đối tượng nhất định (đã đóng:sẽ không sửa được)
Sự khác biệt về tùy chọn chỉ mục không được phát hiện trong so sánh giản đồ cho hai cơ sở dữ liệu (đóng:bên ngoài)
Đề xuất hiển thị điều kiện bộ lọc chỉ mục trong tất cả các chế độ xem thông tin chỉ mục (đã đóng:sẽ không sửa được)
sp_help Kết quả chỉ số phải bao gồm biểu thức Bộ lọc của Chỉ số bộ lọc (hoạt động)
Quá tải sp_help, sp_columns, sp_helpindex cho các tính năng năm 2008 (đã đóng:sẽ không sửa được)


Đối với ba phần cuối cùng, đừng nín thở - Microsoft không có khả năng đầu tư bất kỳ thời gian nào vào các quy trình sp_, DMV, chế độ xem INFORMATION_SCHEMA, v.v. Thay vào đó, hãy xem các bản viết lại sp_helpindex của Kimberly Tripp, bao gồm thông tin về các chỉ mục được lọc cùng với các tính năng mới khác mà Microsoft đã để lại.

Hạn chế của Trình tối ưu hóa

Có một số mục Kết nối mô tả các trường hợp mà chỉ mục đã lọc * có thể * được trình tối ưu hóa sử dụng, nhưng thay vào đó bị bỏ qua. Trong một số trường hợp, chúng không được coi là "lỗi" mà là "lỗ hổng trong chức năng"…

SQL không sử dụng chỉ mục được lọc trên một truy vấn đơn giản (đóng:theo thiết kế)
Kế hoạch thực thi Chỉ mục đã lọc không được tối ưu hóa (đã đóng:sẽ không sửa được)
Chỉ mục đã lọc không được sử dụng và không có tìm kiếm khóa mà không có đầu ra (đã đóng:sẽ không sửa được)
Việc sử dụng Chỉ mục được lọc trên Cột BIT phụ thuộc vào biểu thức SQL chính xác được sử dụng trong mệnh đề WHERE (hoạt động)
Truy vấn máy chủ được liên kết không tối ưu hóa đúng cách khi tồn tại chỉ mục duy nhất được lọc (đã đóng:sẽ không sửa được)
Row_Number () cho kết quả không thể đoán trước trên Máy chủ được liên kết nơi sử dụng Chỉ mục được lọc (đã đóng:không repro)
Chỉ mục được lọc rõ ràng không được QP sử dụng (đóng:theo thiết kế)
Nhận ra các chỉ mục được lọc duy nhất là duy nhất (hoạt động)


Paul White (@SQL_Kiwi) gần đây đã đăng ở đây trên SQLPerformance.com một bài đăng đi sâu vào chi tiết về một số hạn chế của trình tối ưu hóa ở trên.

Và Tim Chapman đã viết một bài đăng tuyệt vời nêu ra một số hạn chế khác của các chỉ mục được lọc - chẳng hạn như không thể so khớp vị từ với một biến cục bộ (đã được sửa vào năm 2008 R2 SP1) và không thể chỉ định một chỉ mục được lọc trong một gợi ý chỉ mục.

Kết luận

Các chỉ mục đã lọc có tiềm năng rất lớn và tôi đã rất kỳ vọng vào chúng khi chúng được giới thiệu lần đầu tiên trong SQL Server 2008. Tuy nhiên, hầu hết các hạn chế xuất hiện với phiên bản đầu tiên của chúng vẫn tồn tại cho đến ngày nay, một phần rưỡi (hoặc hai, tùy thuộc vào bạn. quan điểm) các bản phát hành chính sau này. Ở trên có vẻ giống như một danh sách giặt là khá phong phú về các hạng mục cần được giải quyết, nhưng tôi không có ý cho nó đi theo cách đó. Tôi chỉ muốn mọi người nhận thức được rất nhiều vấn đề tiềm ẩn mà họ có thể cần xem xét khi tận dụng các chỉ mục đã lọc.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bảng thay thế SQL

  2. Quần đảo T-SQL Challenge

  3. Cách phân tích tình trạng của chỉ mục cơ sở dữ liệu

  4. Mang theo đám mây của riêng bạn có sẵn cho DigitalOcean

  5. CẬP NHẬT SQL cho người mới bắt đầu