Một chỉ số một phần (Partial Index) là một chỉ số được xây dựng qua một tập con của một bảng;
tập con đó được một biểu thức điều kiện xác định (được gọi là thuộc tính của chỉ số một phần đó).
Chỉ số đó bao gồm các khoản đầu vào chỉ cho các hàng của các bảng thỏa mãn thuộc tính đó. Các chỉ số một phần là một chức năng chuyên biệt, nhưng có vài tình huống theo đó chúng là hữu dụng.
Một lý do chính cho việc sử dụng một chỉ số một phần là để tránh việc đánh chỉ số các giá trị phổ biến. Vì việc tìm kiếm truy vấn cho một giá trị phổ biến (một giá trị mà tính tới hơn một ít % của tất cả các hàng của bảng) sẽ không sử dụng chỉ số đó, nên không quan trọng trong việc giữ các hàng đó trong chỉ số đó. Điều này làm giảm kích cỡ của chỉ số, nó sẽ làm tăng tốc độ các truy vấn mà sử dụng chỉ số đó. Nó cũng sẽ tăng tốc nhiều hoạt động cập nhật bảng vì chỉ số đó không cần phải được cập nhật trong tất cả các trường hợp. Ví dụ 11-1 chỉ ra một ứng dụng có thể của ý tưởng này.
Ví dụ 11-1. Thiết lập một chỉ số một phần để loại trừ các giá trị phổ biến
Giả sử bạn đang lưu trữ các lưu ký truy cập máy chủ web trong một cơ sở dữ liệu. Hầu hết các truy cập xuất phát từ dãy địa chỉ IP của tổ chức của bạn nhưng một số là từ đâu đó khác (như, các nhân viên trong các kết nối quay số điện thoại).
Nếu các tìm kiếm IP của bạn ban đầu là cho các truy cập bên ngoài, thì bạn có thể không cần đánh chỉ số dãy IP tương ứng với đoạn mạng của tổ chức của bạn.
Giả thiết một bảng giống thế này:
CREATE TABLE access_log ( url varchar,
client_ip inet, ...
);
Để tạo một chỉ số một phần phù hợp với ví dụ của chúng tôi, hãy sử dụng một lệnh như thế này:
CREATE INDEX access_log_client_ip_ix ON access_log (client_ip) WHERE NOT (client_ip > inet ’192.168.100.0’ AND
client_ip < inet ’192.168.100.255’);
Một truy vấn điển hình có thể sử dụng chỉ số này có thể là:
SELECT *
FROM access_log
WHERE url = ’/index.html’ AND client_ip = inet ’212.78.10.32’;
Một truy vấn không thể sử dụng chỉ số này là:
SELECT *
FROM access_log
WHERE client_ip = inet ’192.168.100.23’;
Quan sát thấy rằng dạng chỉ số một phần này đòi hỏi các giá trị phổ biến được xác định trước, sao cho các chỉ số một phần như vậy được sử dụng tốt nhất cho các phân phối dữ liệu không thay đổi.
Các chỉ số đó có thể thỉnh thoảng được tái tạo lại để tinh chỉnh cho các phân phối dữ liệu mới, mà điều này bổ sung thêm cho nỗ lực duy trì.
Sử dụng có thể khác đối với một chỉ số một phần là để loại trừ các giá trị khỏi chỉ số mà tải công việc của truy vấn điển hình không được quan tâm; điều này được chỉ ra trong ví dụ 11-2. Điều này dẫn tới một số ưu điểm như được liệt kê ở trên, nó ngăn chặn các giá trị “không quan tâm” khỏi việc được truy cập thông qua chỉ số đó, thậm chí nếu một sự quét chỉ số có thể có lợi trong trường hợp đó. Rõ ràng, việc thiết lập các chỉ số một phần cho dạng kịch bản này sẽ đòi hỏi nhiều thận trọng và kinh nghiệm hơn.
Ví dụ 11-2. Thiết lập một chỉ số một phần để loại trừ các giá trị không quan tâm
Nếu bạn có một bảng chứa các đơn hàng có hóa đơn và không có hóa đơn, nơi mà các đơn hàng không có hóa đơn chiếm một phần nhỏ của bảng tổng và chúng là các hàng được truy cập nhiều nhất, thì bạn có thể cải thiện hiệu năng bằng việc tạo một chỉ số chỉ trong các hàng không có hóa đơn đó. Lệnh để tạo chỉ số đó có thể trông giống thế này:
CREATE INDEX orders_unbilled_index ON orders (order_nr) WHERE billed is not true;
Một truy vấn có thể sẽ sử dụng chỉ số này có thể là:
SELECT * FROM orders WHERE billed is not true AND order_nr < 10000;
Tuy nhiên, chỉ số đó cũng có thể được sử dụng trong các truy vấn không liên quan tới order_nr, như:
SELECT * FROM orders WHERE billed is not true AND amount > 5000.00;
Điều này không thật hiệu quả như một chỉ số một phần trong cột amount có thể, vì hệ thống phải quét toàn bộ chỉ số. Hơn nữa, nếu có khá ít đơn hàng không có hóa đơn, thì bằng việc sử dụng chỉ số một phần này chỉ tìm thấy các đơn hàng không có hóa đơn có thể là một thành công.
Lưu ý rằng truy vấn đó không thể sử dụng chỉ số này:
SELECT * FROM orders WHERE order_nr = 3501;
Đơn hàng 3501 có thể nằm trong số các đơn hàng có hóa đơn hoặc không có hóa đơn.
Ví dụ 11-2 cũng minh họa rằng cột được đánh chỉ số và cột được sử dụng trong thuộc tính không cần trùng nhau. PostgreSQL hỗ trợ các chỉ số một phần với các thuộc tính tùy chọn, miễn là chỉ các cột của bảng đang được đánh chỉ số có liên quan. Tuy nhiên hãy nhớ trong đầu rằng thuộc tính phải trùng khớp với các điều kiện được sử dụng trong các truy vấn được hỗ trợ để có lợi từ chỉ số đó. Để chính xác, một chỉ số một phần có thể được sử dụng trong một truy vấn chỉ nếu hệ thống đó có thể thừa nhận rằng điều kiện WHERE của truy vấn tự động ngụ ý thuộc tính của chỉ số đó. PostgreSQL không có một trình chứng minh định lý có thể nhận thức được các biểu thức tương đương nhau về mặt toán học được viết ở các dạng khác nhau. (Một trình chứng minh định lý chung như vậy không chỉ là khó để tạo ra, mà nó còn có thể là quá chậm đối với bất kỳ sự sử dụng thực tế nào). Hệ thống có thể nhận biết được các tác động không bằng nhau đơn giản, ví dụ “x < 1” ngụ ý “x < 2”; nếu không thì điều kiện thuộc tính phải chính xác khớp với phần của điều kiện WHERE của truy vấn hoặc chỉ số đó sẽ không được thừa nhận là có khả năng sử dụng. Việc trùng khớp diễn ra trong thời gian lập kế hoạch truy vấn, không trong thời gian chạy. Kết quả là, các mệnh đề truy vấn có tham số không làm việc với một chỉ số một phần. Ví dụ, truy vấn được chuẩn bị với một tham số có thể chỉ định “x < ?” mà sẽ không bao giờ ngụ ý “x < 2” đối với tất cả các giá trị có thể của tham số đó.
Sử dụng có khả năng thứ 3 cho các chỉ số một phần không đòi hỏi chỉ số đó sẽ được sử dụng trong các truy vấn hoàn toàn. Ý tưởng ở đây là để tạo ra một chỉ số duy nhất đối với một tập con của một bảng, như trong ví dụ 11-3. Điều này ép tuân thủ tính độc nhất trong các hàng thỏa mãn thuộc tính chỉ số đó, không có việc ràng buộc các hàng không thỏa mãn.
Ví dụ 11-3. Thiết lập một chỉ số một phần duy nhất
Giả thiết là chúng ta có một bảng mô tả các đầu ra của kiểm thử. Chúng ta muốn đảm bảo rằng chỉ có một khoản đầu vào “thành công” cho một đối tượng được đưa ra và sự kết hợp đích, nhưng có thể có bất kỳ số các khoản đầu vào “không thành công” nào. Đây là một cách để làm điều này:
CREATE TABLE tests ( subject text, target text, success boolean, ...
);
CREATE UNIQUE INDEX tests_success_constraint ON tests (subject, target) WHERE success;
Đây là một tiếp cận đặc biệt hiệu quả khi có ít các kiểm thử thành công và nhiều kiểm thử không thành công.
Cuối cùng, một chỉ số một phần cũng được sử dụng để ghi đè các lựa chọn kế hoạch truy vấn của hệ thống. Hơn nữa, các tập hợp dữ liệu với các phân phối đặc biệt có thể làm cho hệ thống sử dụng một chỉ số khi nó thực sự không nên. Trong trường hợp đó chỉ số có thể được thiết lập sao cho nó là
không sẵn sàng đối với truy vấn vi phạm. Thông thường, PostgreSQL thực hiện các lựa chọn hợp lý về sử dụng chỉ số (như, nó tránh chúng khi truy xuất các giá trị phổ biến, nên ví dụ trước đó thực sự chỉ tiết kiệm kích cỡ của chỉ số, nó không được yêu cầu để tránh sử dụng chỉ số), và các lựa chọn kế hoạch không đúng một cách hiển nhiên là lý do cho một báo cáo lỗi.
Nhớ trong đầu rằng việc thiết lập một chỉ số một phần chỉ ra rằng bạn biết ít nhất như nhiều trình hoạch định truy vấn cũng biết, đặc biệt bạn biết khi một chỉ số có thể có lợi. Việc hình thành tri thức này đòi hỏi kinh nghiệm và sự hiểu biết cách mà các chỉ số trong PostgreSQL làm việc. Trong hầu hết các trường hợp, ưu thế của một chỉ số một phần đối với một chỉ số thông thường sẽ là tối thiểu.
Nhiều thông tin hơn về các chỉ số một phần có thể thấy trong Trường hợp cho các chỉ số một phần, Việc đánh chỉ số một phần trong PostgreSQL: dự án nghiên cứu, và các chỉ số một phần được khái quát hóa (phiên bản được nắm bắt).