2012-02-03 40 views
7

Để truy vấn top-n hàng trong Oracle, nói chung là sử dụng ROWNUM. Vì vậy, các truy vấn sau đây có vẻ ok (được 5 thanh toán gần đây nhất):Hiệu suất ROWNUM của Oracle

select a.paydate, a.amount 
from (
    select t.paydate, t.amount 
    from payments t 
    where t.some_id = id 
    order by t.paydate desc 
) a 
where rownum <= 5; 

Nhưng đối với bảng rất lớn, nó không hiệu quả - đối với tôi nó chạy ~ 10 phút. Vì vậy, tôi đã cố gắng truy vấn khác, và tôi đã kết thúc với một này mà chạy cho ít hơn một giây:

select * 
from (
    select a.*, rownum 
    from (select t.paydate, t.amount 
     from payments t 
     where t.some_id = id 
     order by t.paydate desc) a 
) 
where rownum <= 5; 

Để tìm hiểu những gì đang xảy ra, tôi nhìn kế hoạch thực hiện cho mỗi truy vấn. Đối với truy vấn đầu tiên:

SELECT STATEMENT, GOAL = ALL_ROWS 7 5 175 
COUNT STOPKEY   
VIEW 7 5 175 
TABLE ACCESS BY INDEX ROWID 7 316576866 6331537320 
INDEX FULL SCAN DESCENDING 4 6 

Và đối với thứ hai:

SELECT STATEMENT, GOAL = ALL_ROWS 86 5 175 
COUNT STOPKEY   
VIEW 86 81 2835 
COUNT   
VIEW 86 81 1782 
SORT ORDER BY 86 81 1620 
TABLE ACCESS BY INDEX ROWID 85 81 1620 
INDEX RANGE SCAN 4 81 

Rõ ràng, đó là INDEX ĐẦY ĐỦ SCAN Giảm dần mà làm cho truy vấn đầu tiên không hiệu quả cho các bảng lớn. Nhưng tôi không thể phân biệt được logic của hai truy vấn bằng cách nhìn vào chúng. Bất cứ ai có thể giải thích cho tôi sự khác biệt hợp lý giữa hai truy vấn bằng ngôn ngữ của con người?

Cảm ơn trước!

+2

id là biến số liên kết, không (phải là: id?) Nếu vậy, giá trị nào được sử dụng (giống nhau?) – tbone

+2

Tôi không nghĩ rằng 'rownum' bạn đang sử dụng cho bộ lọc trong phiên bản thứ hai là được đảm bảo giống như trong lần đầu tiên; nghĩ rằng bạn cần phải bí danh truy vấn thứ hai của bạn và tham chiếu đó, hoặc thêm 'thứ tự bởi rownum' trong truy vấn đối với' a'? Tôi nghi ngờ điều này đang ảnh hưởng đến tốc độ mặc dù. –

Trả lời

3

Trước hết, như đã đề cập trong nhận xét của Alex, tôi không chắc chắn rằng phiên bản thứ hai của bạn được đảm bảo 100% để cung cấp cho bạn các hàng phù hợp - vì khối "trung bình" của truy vấn không rõ ràng order by , Oracle không có nghĩa vụ chuyển các hàng lên tới khối truy vấn bên ngoài theo bất kỳ thứ tự cụ thể nào. Tuy nhiên, dường như không có lý do cụ thể nào mà nó sẽ thay đổi thứ tự các hàng được truyền từ khối trong cùng, vì vậy trong thực tế nó có thể sẽ hoạt động.

Và đây là lý do tại sao Oracle chọn một gói khác cho truy vấn thứ hai - về mặt logic không thể áp dụng thao tác STOPKEY cho khối truy vấn trong cùng. Tôi nghĩ trong trường hợp đầu tiên, trình tối ưu hóa giả định rằng các giá trị id được phân phối tốt và, đối với bất kỳ giá trị cụ thể nào, có thể có một số giao dịch rất gần đây. Vì nó có thể thấy rằng nó chỉ cần tìm 5 kết quả gần đây nhất, nó tính toán rằng có vẻ hiệu quả hơn khi quét các hàng theo thứ tự giảm dần của paydate bằng cách sử dụng chỉ mục, tra cứu id tương ứng và dữ liệu khác từ bảng và dừng lại khi nó được tìm thấy trong 5 trận đấu đầu tiên. Tôi nghi ngờ rằng bạn sẽ thấy hiệu suất rất khác nhau cho truy vấn này tùy thuộc vào giá trị id cụ thể mà bạn sử dụng - nếu id có nhiều hoạt động gần đây, các hàng sẽ được tìm thấy rất nhanh, nhưng nếu không, quét chỉ mục có thể phải làm nhiều việc hơn.

Trong trường hợp thứ hai, tôi tin rằng nó không thể áp dụng tối ưu hóa STOPKEY cho khối trong cùng do lớp bổ sung làm tổ. Trong trường hợp đó, việc quét toàn bộ chỉ mục sẽ trở nên kém hấp dẫn hơn nhiều, vì nó sẽ luôn cần quét toàn bộ chỉ mục. Do đó, nó chọn thực hiện tìm kiếm chỉ mục trên id (tôi giả định) theo sau là một loại thực tế vào ngày đó. Nếu giá trị id cho phù hợp với một tập con nhỏ của hàng, điều này có thể hiệu quả hơn - nhưng nếu bạn cung cấp số id có nhiều hàng trải rộng trên toàn bộ bảng, tôi sẽ mong đợi nó trở nên chậm hơn, vì nó sẽ có để truy cập và sắp xếp nhiều hàng.

Vì vậy, tôi đoán rằng các thử nghiệm của bạn đã sử dụng giá trị id có hàng tương đối ít mà không phải là rất gần đây.Nếu đây là trường hợp sử dụng điển hình, thì truy vấn thứ hai có thể tốt hơn cho bạn (một lần nữa, với thông báo trước rằng tôi không chắc chắn về mặt kỹ thuật được đảm bảo để tạo ra tập kết quả chính xác). Nhưng nếu các giá trị thông thường có nhiều khả năng có nhiều hàng phù hợp và/hoặc nhiều khả năng có 5 hàng gần đây thì truy vấn và kế hoạch đầu tiên có thể tốt hơn.

+0

Giải thích tuyệt vời! Cảm ơn. @ Alex: có vẻ tốt hơn là nên thêm 'order by rownum' vì nó thêm" SORT ORDER BY STOPRKEY "trong kế hoạch exec, trong khi aliasing' rownum' loại bỏ "COUNT STOPKEY" trong kế hoạch exec. Nhưng, như bạn đã lưu ý, tôi đã không thấy những thay đổi về tốc độ. – Bazi