2010-03-18 27 views
12

Tôi có một loạt các truy vấn cực kỳ tương tự mà tôi chạy với bảng 1,4 tỷ bản ghi (có chỉ mục), vấn đề duy nhất là ít nhất 10% các truy vấn đó mất> 100x thời gian để thực thi nhiều hơn các truy vấn khác.Làm thế nào để buộc oracle sử dụng quét phạm vi chỉ mục?

Tôi đã chạy một kế hoạch giải thích và nhận thấy rằng đối với các truy vấn nhanh (khoảng 90%), Oracle đang sử dụng quét phạm vi chỉ mục; trên những cái chậm, nó sử dụng quét chỉ mục đầy đủ.

Có cách nào buộc Oracle thực hiện quét phạm vi chỉ mục không?

Trả lời

12

tôi đề nghị các phương pháp sau đây: -

  • Nhận một giải thích kế hoạch trên báo cáo kết quả chậm
  • Sử dụng một gợi ý INDEX, có được một kế hoạch giải thích về việc sử dụng các chỉ số

Bạn sẽ lưu ý rằng chi phí của kế hoạch INDEX lớn hơn. Đây là lý do tại sao Oracle không chọn kế hoạch chỉ mục. Chi phí là ước tính của Oracle dựa trên số liệu thống kê của nó và các giả định khác nhau.

Nếu chi phí ước tính của kế hoạch lớn hơn, nhưng thực sự chạy nhanh hơn thì ước tính là sai. Công việc của bạn là tìm ra lý do tại sao ước tính sai và chính xác điều đó. Sau đó, Oracle sẽ chọn đúng kế hoạch cho tuyên bố này và những người khác trên đó là của chính nó.

Để tìm hiểu lý do sai, hãy xem số hàng dự kiến ​​trong kế hoạch. Có thể bạn sẽ tìm thấy một trong số đó là thứ tự độ lớn. Điều này có thể do các giá trị cột được phân phối không thống nhất, các số liệu thống kê cũ, các cột có liên quan với nhau, v.v.

Để thu thập số liệu thống kê tốt hơn và gợi ý các số liệu tốt hơn. Sau đó, nó sẽ ước tính chi phí chính xác và đưa ra kế hoạch nhanh nhất.

Nếu bạn đăng thêm thông tin, tôi có thể nhận xét thêm.

+3

Vì đây là phạm vi quét, tôi tự hỏi liệu các truy vấn 'chậm' có hoạt động với phạm vi lớn hơn (ví dụ: một năm thay vì một tuần). Trong trường hợp đó, bạn mong đợi chúng chậm hơn đáng kể. Tại một số điểm, khi phạm vi đủ lớn, sẽ có ý nghĩa khi chuyển từ chỉ mục sang quét toàn bộ. Cho dù Oracle đã đoán điểm đó đúng là một vấn đề khác. –

+0

Hơn nữa, nếu nó quét toàn bộ chỉ mục và truy vấn của bạn đang tham gia vào một bảng khác, tôi đoán nó không tham gia qua vòng lặp lồng nhau - có thể chuyển sang băm hoặc hợp nhất hoặc tham gia các bảng theo thứ tự khác. Nếu các truy vấn chậm "nên" nhanh hơn (nghĩa là chúng không phải là IRL truy vấn phần trăm đáng kể của bảng), bạn sẽ có thể quay lại phạm vi quét bằng cách gợi ý cho các vòng lồng nhau (với gợi ý 'USE_NL' phù hợp). –

-2

Tôi đã thấy gợi ý bị bỏ qua bởi Oracle.

Gần đây, DBA của chúng tôi sử dụng "optimizer_index_cost_adj" và nó sử dụng chỉ mục. Đây là tham số Oracle nhưng bạn có thể sử dụng nó làm cấp phiên.

100 là giá trị mặc định và chúng tôi đã sử dụng 10 làm tham số.

+0

optimizer_index_cost_adj ảnh hưởng đến TẤT CẢ các phép tính được thực hiện bởi trình tối ưu hóa khi xem xét bất kỳ chỉ mục nào trên toàn hệ thống - thay đổi nó phải được thực hiện cẩn thận, có tính đến ảnh hưởng chung của nó trên một hệ thống. –

+0

Đó là quan điểm của tôi. Khi nó được sử dụng, nó nên được sử dụng bởi tham số cấp phiên để nó sẽ không ảnh hưởng đến bất kỳ truy vấn nào khác. – exiter2000

+0

Hãy nhớ rằng gợi ý là gợi ý và rằng trình tối ưu hóa có thể quyết định không sử dụng nó. – DJPeter

2

Nếu bạn muốn biết tại sao trình tối ưu hóa đưa ra quyết định, bạn cần sử dụng theo dõi 10053.

SQL> alter session set events '10053 trace name context forever, level 1'; 

Sau đó chạy các kế hoạch giải thích cho truy vấn nhanh mẫu và truy vấn mẫu chậm. Trong thư mục kết xuất người dùng, bạn sẽ nhận được các tệp theo dõi chi tiết các cây quyết định mà CBO đi qua. Một nơi nào đó trong những tập tin đó, bạn sẽ tìm thấy những lý do tại sao nó chọn quét toàn bộ chỉ mục trên quét phạm vi chỉ mục.

Tôi không nói rằng tệp theo dõi dễ đọc. Tài nguyên tốt nhất để hiểu chúng là giấy trắng tuyệt vời của Wolfgang Breitling "A look under the hood of CBO" (PDF)

-1

bạn có thể sử dụng gợi ý sql oracle.bạn có thể buộc phải sử dụng chỉ số cụ thể hoặc loại trừ chỉ số kiểm tra tài liệu

http://psoug.org/reference/hints.html http://www.adp-gmbh.ch/ora/sql/hints/index.html

như chọn/* + index (scott.emp ix_emp) */từ scott.emp emp_alias

+1

Điều đó sẽ làm cho Oracle sử dụng một chỉ mục, nhưng sẽ không nhất thiết buộc phải quét phạm vi chỉ mục thay vì quét chỉ mục đầy đủ. –

+0

Nếu chỉ mục của bạn dựa trên các giá trị cột không phải là duy nhất, nó chắc chắn sẽ chỉ cho Quét Phạm vi Chỉ mục. Để làm như vậy bằng gợi ý, hãy sử dụng gợi ý INDEX và nó sẽ ổn. nếu không quét chỉ mục đầy đủ yêu cầu – mermerkaya

+0

Có thể 99,9% thời gian sẽ chọn quét phạm vi chỉ mục một cách chính xác. Nhưng đôi khi Oracle chọn quét toàn bộ chỉ mục thay thế. Có một gợi ý để nói với Oracle rằng không nên sử dụng quét chỉ mục * nhanh * đầy đủ, nhưng theo như tôi biết thì không có cách nào để nói với Oracle không sử dụng quét chỉ mục đầy đủ. –

7

Để "buộc" Oracle sử dụng quét phạm vi chỉ mục, chỉ cần sử dụng gợi ý tối ưu hóa INDEX_RS_ASC. Ví dụ:

CREATE TABLE mytable (a NUMBER NOT NULL, b NUMBER NOT NULL, c CHAR(10)) NOLOGGING; 

INSERT /*+ APPEND */ INTO mytable(a,b,c) 
SELECT level, mod(level,100)+1, 'a' FROM dual CONNECT BY level <= 1E6; 

CREATE INDEX myindex_ba ON mytable(b, a); 
EXECUTE dbms_stats.gather_table_stats(NULL,'mytable'); 

SELECT /*+ FULL(m)   */ b FROM mytable m WHERE b=10; -- full table scan 
SELECT /*+ INDEX_RS_ASC(m) */ b FROM mytable m WHERE b=10; -- index range scan 
SELECT /*+ INDEX_FFS(m) */ b FROM mytable m WHERE b=10; -- index fast full scan 

Điều này sẽ làm cho truy vấn của bạn thực sự chạy nhanh hơn phụ thuộc vào nhiều yếu tố như chọn lọc giá trị được lập chỉ mục hoặc thứ tự vật lý của các hàng trong bảng của bạn. Ví dụ, nếu bạn thay đổi truy vấn để WHERE b BETWEEN 10 AND <xxx>, các chi phí sau xuất hiện trong kế hoạch thực hiện trên máy tính của tôi:

b BETWEEN 10 AND 10  20  40  80 
FULL    749 750  751 752 
INDEX_RS_ASC  29 325  865 1943 
INDEX_FFS   597 598  599 601 

Nếu bạn thay đổi câu hỏi rất nhẹ để không chỉ chọn cột được lập chỉ mục b, mà còn khác, các cột không phải chỉ mục, chi phí thay đổi đáng kể:

b BETWEEN 10 AND 10  20  40  80 
FULL    749 750  751 754 
INDEX_RS_ASC  3352 40540 108215 243563 
INDEX_FFS   3352 40540 108215 243563 
+0

Tôi đã thay đổi INDEX_RS thành INDEX_RS_ASC. Cả hai đều hoạt động, nhưng dựa trên V $ SQL_HINT và [this article] (http://jonathanlewis.wordpress.com/2007/06/17/hints-again/), INDEX_RS_ASC có vẻ là gợi ý chính thức, mặc dù cả hai đều thực sự không có giấy tờ. Thật không may, gợi ý này vẫn không giải quyết được vấn đề cụ thể của tôi, vì vậy nó không phải lúc nào cũng hiệu quả. Nhưng nó hoạt động ít nhất là đôi khi, như kịch bản của bạn thể hiện rõ ràng. –

Các vấn đề liên quan