2009-07-06 71 views
10

Tôi đang sử dụng Oracle và tôi có một bảng rất lớn. Tôi cần phải kiểm tra sự tồn tại của bất kỳ hàng nào đáp ứng một số tiêu chí đơn giản. Cách tốt nhất để thực hiện điều này bằng cách sử dụng SQL đơn giản là gì?Truy vấn nhanh nhất để kiểm tra sự tồn tại của một hàng trong Oracle?

Dưới đây là dự đoán tốt nhất của tôi, và trong khi nó có thể bật ra được đủ nhanh cho các mục đích của tôi, tôi rất muốn học một cách kinh điển về cơ bản làm SQL Server của "tồn tại" trong Oracle:

select count(x_id) from x where x.col_a = value_a and x.col_b = value_b; 

Số đếm() sau đó sẽ được trả về dưới dạng boolean trong một cấp khác. Điểm chính là tôi muốn Oracle làm tối thiểu cho truy vấn này - tôi chỉ cần biết nếu có bất kỳ hàng nào phù hợp với tiêu chí.

Và có, những cột này chắc chắn sẽ được lập chỉ mục.

Trả lời

16

Sử dụng COUNT (*) là OK nếu bạn cũng sử dụng rownum = 1:

declare 
    l_cnt integer; 
begin 
    select count(*) 
    into l_cnt 
    from x 
    where x.col_a = value_a 
    and x.col_b = value_b 
    and rownum = 1; 
end; 

này sẽ luôn luôn trả về một hàng, vì vậy không cần thiết phải xử lý bất kỳ ngoại lệ NO_DATA_FOUND nào. Giá trị của l_cnt sẽ là 0 (không có hàng) hoặc 1 (ít nhất 1 hàng tồn tại).

+1

@Tony - bạn sẽ làm một số (*) thay vì một EXISTS? Với tôi, một EXISTS có vẻ tự nhiên hơn ngay cả khi bạn cần phải giải quyết ngoại lệ. –

+0

Bạn có nghĩa là "chọn 1 từ hai nơi tồn tại (...)"? Tôi sẽ không, nhưng có thể hiểu tại sao một số sẽ. Những gì thực sự muốn được trully tự nhiên là một PL/SQL xây dựng như "NẾU tồn tại (chọn ...) THEN ..."! –

+0

Tôi lười biếng ở đây vì không tự mình thử nghiệm, nhưng sẽ không tính (x_id) nhanh hơn đếm (*), hoặc là thông dịch viên sql đủ thông minh để thấy rằng nó không thực sự cần mở rộng "*" ? –

5
SELECT NULL 
FROM x 
WHERE x.col_a = value_a 
     AND x.col_b = value_b 
     AND rownum = 1 

COUNT(*) chắc chắn không phải là cách tốt nhất vì nó sẽ cần phải đếm tất cả các hàng, trong khi ROWNUM = 1 lợi nhuận ngay khi nó tìm thấy hàng phù hợp đầu tiên.

Dưới đây là đoạn code PL/SQL:

DECLARE 
     ex INT; 
BEGIN 
     BEGIN 
       SELECT NULL 
       INTO ex 
       FROM dual 
       WHERE 1 = 1 
         AND rownum = 1; 
       DBMS_OUTPUT.put_line('found'); 
     EXCEPTION 
     WHEN no_data_found THEN 
       DBMS_OUTPUT.put_line('not found'); 
     END; 
END; 
+0

Thậm chí có thể là gợi ý FIRST_ROWS? Trình tối ưu hóa nên thực hiện điều này một cách rõ ràng khi nó nhìn thấy báo cáo tổng quát = 1 mà tôi nghĩ. SELECT/* + FIRST_ROWS (n) */NULL –

+0

@Robert: tất nhiên nó sẽ không làm tổn thương thêm, nhưng nó thực sự chỉ hoạt động trong các kết nối (nó làm cho trình tối ưu hóa thích NESTED LOOP hơn HASH JOIN) – Quassnoi

+1

@ Quassnoi: Tôi nghĩ nó cũng làm cho người lập chỉ mục 'hạnh phúc hơn'. –

1
begin 
select 'row DOES exist' 
    into ls_result 
from dual 
where exists (select null from x where x.col_a = value_a and x.col_b = value_b); 
exception 
when no_data_found then 
    ls_result := ' row does NOT exist'; 
end; 
7

Tôi nghĩ rằng việc sử dụng EXISTS mang lại câu trả lời tự nhiên hơn cho câu hỏi hơn là cố gắng tối ưu hóa COUNT truy vấn bằng ROWNUM.

Hãy để Oracle thực hiện tối ưu hóa ROWNUM cho bạn.

create or replace function is_exists (
     p_value_a varchar2, 
     p_value_b varchar2) 
     return boolean 
is 

    v_exists varchar2(1 char); 

begin 

    begin 
     select 'Y' into v_exists from dual 
     where exists 
      (select 1 from x where x.col_a = p_value_a and x.col_b = p_value_a); 

    exception 

     when no_data_found then 

      v_exists := null; 

    end; 

    return v_exists is not null; 

end is_exists; 
Các vấn đề liên quan