Để hiểu rõ hơn điều gì đang xảy ra, hãy thử cách này:
explain plan set statement_id = 'query1' for
SELECT count(ck.id)
FROM claim_key ck
WHERE (ck.dte_of_srvce > (SYSDATE - INTERVAL '30' DAY))
AND ck.clm_type = 5
AND ck.prgrm_id = 1;
và sau đó:
select *
from table(dbms_xplan.display(statement_id=>'query1'));
Tôi đoán bạn sẽ thấy một dòng cho biết BẢNG TRUY CẬP ĐẦY ĐỦ trên register_key.
Sau đó, hãy thử:
explain plan set statement_id = 'query2' for
SELECT count(ck.id)
FROM claim_key ck
WHERE (ck.dte_of_srvce > (SYSDATE - INTERVAL '30' DAY))
AND ck.clm_type = 5;
select *
from table(dbms_xplan.display(statement_id=>'query2'));
và kiểm tra xem nó (có lẽ) đang sử dụng chỉ mục nào. Điều đó sẽ cung cấp cho bạn ý tưởng về những gì cơ sở dữ liệu đang làm, giúp tìm ra tại sao nó đang làm điều đó.
Được rồi, với các kế hoạch giải thích của bạn, đó là một ví dụ cổ điển về "chỉ mục không phải lúc nào cũng tốt, quét bảng không phải lúc nào cũng xấu".
INDEX SKIP SCAN là nơi cơ sở dữ liệu có thể cố gắng sử dụng một chỉ mục ngay cả khi cột đầu của chỉ mục thậm chí không được sử dụng. Về cơ bản, nếu chỉ mục của bạn trông như thế này (đơn giản hóa quá mức):
COL1 COL2 ROWID
A X 1 <--
A Y 2
A Z 3
B X 4 <--
B Y 5
B Z 6
và điều kiện của bạn là WHERE col2 ='X', quét bỏ qua chỉ mục cho biết hãy xem qua từng kết hợp trong COL1 cho nơi col2 ='X'. Nó "bỏ qua" các giá trị trong col1 sau khi tìm thấy kết quả khớp (ví dụ:col1 =A, col2 =X) xuống nơi giá trị thay đổi (col1 =B, sau đó là col1 =C, v.v.) và tìm kiếm các kết quả phù hợp hơn.
Vấn đề cần lưu ý là các chỉ mục (nói chung!) Hoạt động như thế này:1) tìm rowid tiếp theo trong chỉ mục nơi giá trị được tìm thấy2) chuyển đến khối bảng có rowid đó (TABLE ACCESS BY INDEX ROWID) 3) lặp lại cho đến khi không còn khớp nào nữa được tìm thấy.
(Đối với quá trình quét bỏ qua, nó cũng sẽ phải trả chi phí để tìm ra vị trí thay đổi giá trị tiếp theo cho các cột hàng đầu.)
Điều này là tốt và tốt đối với một số ít hàng, nhưng phải tuân theo quy luật lợi nhuận giảm dần; nó không phải là tuyệt vời khi bạn có một số lượng lớn các hàng. Đó là bởi vì nó phải đọc khối chỉ mục, sau đó là khối bảng, sau đó là khối chỉ mục, khối bảng (ngay cả khi khối bảng đã được đọc trước đó.)
Việc quét toàn bộ bảng chỉ "cày" qua dữ liệu một phần nhờ vào ... các lần đọc đa khối. Cơ sở dữ liệu có thể đọc nhiều khối từ đĩa trong một lần đọc và không đọc cùng một khối nhiều lần.
INDEX FAST FULL SCAN về cơ bản coi I_CLAIM_KEY_002 là một bảng. Tất cả những gì bạn cần trong truy vấn có thể được trả lời bởi chỉ mục; không cần TRUY CẬP BẢNG. (Tôi đoán I_CLAIM_KEY_002 được định nghĩa là clnt_id, dte_of_srvce và clnt_id hoặc dte_of_srvce không thể null. Vì ck.id không phải là thuộc tính null, nên số lượng trên ck.id giống như số lượng trên ck.clnt_id.)
Vì vậy, đối với truy vấn ban đầu của bạn, trừ khi bạn muốn điều chỉnh lại các chỉ mục của mình, hãy thử điều này:
SELECT /*+ FULL(ck) */ count(ck.id)
FROM claim_key ck
WHERE (ck.dte_of_srvce > (SYSDATE - INTERVAL '30' DAY))
AND ck.clm_type = 5
AND ck.prgrm_id = 1
điều này sẽ buộc phải quét toàn bộ bảng trên register_key (ck) và bạn có thể thấy hiệu suất tương tự như hai phần còn lại. (Kiểm tra xem đây có phải là trường hợp đầu tiên đặt tiền tố truy vấn với "giải thích bộ kế hoạch statement_id ='query_hint' cho" và chạy truy vấn dbms_xplan trước khi bạn chạy nó hay không.)
(Bây giờ bạn sẽ hỏi "tôi có muốn đưa ra các gợi ý như vậy mọi lúc không"? Vui lòng không. Đây chỉ là để thử nghiệm. Đây chỉ là để kiểm tra xem FTS có tốt hơn INDEX SKIP SCAN không . Nếu đúng như vậy, thì bạn cần tìm hiểu lý do tại sao. :)
Dù sao thì ... tôi hy vọng điều đó có ý nghĩa ... tôi có ý nghĩa.