2009-04-06 27 views
15

Chúng tôi có Oracle 10g và chúng tôi cần truy vấn 1 bảng (không có tham gia) và lọc ra các hàng có 1 cột là null. Khi chúng tôi làm điều này - WHERE OurColumn IS NOT NULL - chúng tôi có được một bảng quét toàn bộ trên một bảng rất lớn - BAD BAD BAD. Cột có một chỉ mục trên nó nhưng nó bị bỏ qua trong trường hợp này. Có giải pháp nào cho điều này không?Oracle 10g - tối ưu hóa KHÔNG CÓ NULL

Cảm ơn

Trả lời

20

Trình tối ưu hóa cho rằng quét toàn bộ bảng sẽ tốt hơn.

Nếu chỉ có một vài NULL hàng, trình tối ưu hóa là đúng.

Nếu bạn biết chắc chắn rằng truy cập index sẽ nhanh hơn (có nghĩa là, bạn có nhiều hơn 75% hàng với col1 IS NULL), sau đó gợi ý truy vấn của bạn:

SELECT /*+ INDEX (t index_name_on_col1) */ 
     * 
FROM mytable t 
WHERE col1 IS NOT NULL 

Tại sao 75%?

Bởi vì việc sử dụng để truy xuất các giá trị không được bao gồm trong chỉ mục ngụ ý sự tham gia ẩn trên ROWID, chi phí khoảng 4 nhiều lần quét bảng.

Nếu phạm vi chỉ mục bao gồm nhiều hơn 25% hàng, việc quét bảng thường nhanh hơn.

Như đã đề cập bởi Tony Andrews, hệ số phân cụm là phương pháp chính xác hơn để đo lường giá trị này, nhưng 25% vẫn là nguyên tắc chung.

+1

Quassnoi, bạn nhận được 75% ở đâu? Nếu có hàng triệu hàng và chỉ có một hàng là null, tại sao việc sử dụng chỉ mục trên các cột đó chậm hơn so với quét bảng? – tpdi

+1

Bởi vì chỉ mục ngụ ý một kết nối bị ẩn trên ROWID, chi phí cao gấp 4 lần so với quét bảng. Độ chọn lọc chỉ số có thấp hơn 25% hay không, việc quét bảng thường nhanh hơn. – Quassnoi

+2

Khi quét toàn bộ bảng, bạn chỉ cần lặp qua tất cả các hàng trong bảng; nếu bạn thực hiện quét chỉ mục, trước tiên bạn phải đọc chỉ mục và sau đó đọc bảng. Từ một thời điểm nhất định, chi phí đọc chỉ mục cao hơn chỉ đọc toàn bộ bảng. – andri

2

Nếu bạn đang thực hiện lựa chọn *, bạn có thể thực hiện quét bảng thay vì sử dụng chỉ mục. Nếu bạn biết bạn quan tâm đến cột nào, bạn có thể tạo chỉ mục được bao phủ bằng các cột màu đó cộng với cột bạn đang áp dụng điều kiện IS NOT NULL.

0

Tạo chỉ mục trên cột đó.

Để đảm bảo chỉ mục được sử dụng, chỉ mục đó phải nằm trên chỉ mục và các cột khác ở vị trí đó.

ocdecio trả lời:

Nếu bạn đang làm một chọn *, sau đó nó sẽ làm cho tinh thần để làm một bảng quét thay vì sử dụng các chỉ số.

Điều đó không đúng; một chỉ mục sẽ được sử dụng nếu có chỉ mục phù hợp với mệnh đề where của bạn, và trình tối ưu hóa truy vấn quyết định sử dụng chỉ mục đó sẽ nhanh hơn so với thực hiện quét bảng. Nếu không có chỉ số, hoặc không có chỉ mục phù hợp, chỉ sau đó phải thực hiện quét bảng.

+0

Nhận xét tuyệt vời về Chọn * Chỉ cần làm rõ mặc dù - chúng tôi không bao giờ sử dụng SELECT * vì các lý do khác - chúng tôi luôn bao gồm danh sách cột của chúng tôi trong mệnh đề CHỌN. –

15

Trình tối ưu hóa sẽ đưa ra quyết định dựa trên chi phí tương đối của quá trình quét toàn bộ bảng và sử dụng chỉ mục. Điều này chủ yếu đi xuống đến bao nhiêu khối sẽ phải được đọc để đáp ứng các truy vấn. Quy tắc ngón tay cái 25%/75% được đề cập trong câu trả lời khác là đơn giản: trong một số trường hợp, quét toàn bộ bảng sẽ có ý nghĩa ngay cả khi nhận được 1% số hàng - tức là nếu những hàng đó xảy ra xung quanh nhiều khối.

Ví dụ, hãy xem xét bảng này:

SQL> create table t1 as select object_id, object_name from all_objects; 

Table created. 
SQL> alter table t1 modify object_id null; 

Table altered. 

SQL> update t1 set object_id = null 
    2 where mod(object_id,100) != 0 
    3/

84558 rows updated. 

SQL> analyze table t1 compute statistics; 

Table analyzed. 

SQL> select count(*) from t1 where object_id is not null; 

    COUNT(*) 
---------- 
     861  

Như bạn có thể thấy, chỉ có khoảng 1% của các hàng trong T1 có một object_id phi null.Nhưng do cách tôi xây dựng bảng, 861 hàng này sẽ được lan truyền nhiều hơn hoặc ít hơn xung quanh bảng. Do đó, truy vấn:

select * from t1 where object_id is not null; 

có khả năng truy cập hầu hết mọi khối trong T1 để nhận dữ liệu, ngay cả khi trình tối ưu hóa đã sử dụng chỉ mục. Nó có ý nghĩa sau đó để phân chia với các chỉ số và đi cho một bảng đầy đủ quét!

Một thống kê quan trọng để giúp xác định tình trạng này là yếu tố chỉ số phân nhóm:

SQL> select clustering_factor from user_indexes where index_name='T1_IDX'; 

CLUSTERING_FACTOR 
----------------- 
       460 

này giá trị 460 là khá cao (so với 861 hàng trong index), và gợi ý rằng một bảng quét toàn bộ sẽ được dùng. Xem this DBAZine article on clustering factors.

1

Nó có thể phụ thuộc vào loại chỉ mục bạn có trên bảng.

Hầu hết chỉ mục B-tree làm không lưu trữ các mục nhập rỗng. Chỉ mục bitmap làm lưu trữ các mục nhập rỗng.

Vì vậy, nếu bạn có:

select * from mytable nơi mycolumn là null

và bạn có một chỉ số B-cây tiêu chuẩn trên mycolumn, sau đó truy vấn không thể sử dụng chỉ mục là "null" không có trong chỉ mục.

(Nếu chỉ số này so với nhiều cột, và một trong các cột được đánh chỉ mục không phải là null thì sẽ có một mục trong chỉ mục.)

+1

Câu hỏi liên quan đến tra cứu 'không phải là null', không phải' là null'. – KajMagnus

+0

Tuy nhiên, đây là thông tin hữu ích –

0

Nó cũng đáng kiểm tra xem liệu thống kê của Oracle trên bàn lên đến ngày. Có thể không biết rằng việc quét toàn bộ bảng sẽ chậm hơn.

0

Oracle cơ sở dữ liệu không chỉ số giá trị null ở tất cả trong thường xuyên (b-tree) lập chỉ mục, vì vậy nó không thể sử dụng nó cũng không bạn có thể' t lực lượng oracle cơ sở dữ liệu để sử dụng nó.

BR

+0

Câu hỏi này là về 'KHÔNG phải là null'. Tất cả các giá trị có liên quan sẽ có trong chỉ mục. –

0

Chỉ nên thực hiện các gợi ý làm công việc thay vì giải pháp.

Như đã đề cập trong các câu trả lời khác, giá trị rỗng không có sẵn trong chỉ mục B-TREE.

Vì bạn biết rằng bạn có các giá trị chủ yếu là rỗng trong cột này, bạn có thể thay thế giá trị null bằng một phạm vi chẳng hạn.

Đó thực sự phụ thuộc vào cột của bạn và bản chất của dữ liệu của bạn nhưng thông thường, nếu cột của bạn là một loại ngày ví dụ:

where mydatecolumn is not null có thể được dịch theo một quy tắc nói: Tôi muốn tất cả các hàng trong đó có một ngày.

Sau đó, bạn chắc chắn nhất có thể làm điều này: nơi mydatecolumn < = sysdate (trong oracle)

này sẽ trả lại toàn bộ hàng với một ngày và ommit giá trị null trong khi lợi dụng các chỉ mục trên cột đó mà không sử dụng bất kỳ gợi ý.