2009-12-01 43 views
6

Bảng có khóa chính thay thế được tạo ra từ trình tự. Thật không may, trình tự này được sử dụng để tạo khóa cho một số bảng khác (tôi đã không thiết kế nó và tôi không thể thay đổi nó).Chọn `n` các bản ghi được chèn cuối cùng trong bảng - oracle

Cách nhanh nhất để chọn n bản ghi được chèn vào cuối cùng trong Oracle, được sắp xếp theo id theo thứ tự giảm dần (lần chèn cuối cùng ở trên cùng) là gì?

n là một số lượng tương đối nhỏ - số lượng hồ sơ để hiển thị trên trang - có lẽ không lớn hơn 50.

Bảng hiện có 30.000.000 hồ sơ với 10-15 ngàn kỷ lục mới hàng ngày.

Cơ sở dữ liệu là Oracle 10g.

Edit:
Trong câu trả lời cho một lời nhận xét: Câu hỏi này đã được thúc đẩy với kế hoạch thực hiện cho truy vấn:

select * from MyTable order by primarykeyfield desc 

kế hoạch thực hiện là:

--------------------------------------------- 
| Id | Operation   | Name  |  
--------------------------------------------- 
| 0 | SELECT STATEMENT |    | 
| 1 | SORT ORDER BY  |    | 
| 2 | TABLE ACCESS FULL| MyTable  | 
--------------------------------------------- 

Tôi rất ngạc nhiên rằng Oracle muốn để thực hiện quét toàn bộ bảng và sắp xếp khi nó có chỉ mục trên trường sắp xếp.

Truy vấn từ câu trả lời được chấp nhận sử dụng chỉ mục và tránh sắp xếp.

Chỉnh sửa 2:
Re. Nhận xét của APC: Phân loại là một phần khiến tôi ngạc nhiên. Tôi hy vọng rằng Oracle sẽ sử dụng chỉ mục để lấy các hàng theo thứ tự mong muốn. kế hoạch thực hiện cho truy vấn:

select * from (select * from arh_promjene order by promjena_id desc) x 
    where rownum < 50000000 

sử dụng chỉ số thay vì truy cập bảng đầy đủ và sắp xếp (thông báo tình trạng rownum < 50.000.000 - đây là cách nhiều hơn số lượng các bản ghi trong bảng và Oracle đều biết rằng nó nên lấy tất cả hồ sơ từ bảng). Truy vấn này trả về tất cả các hàng như truy vấn đầu tiên, nhưng với kế hoạch thực hiện như sau:

| Id | Operation      | Name   | 
------------------------------------------------------- 
| 0 | SELECT STATEMENT    |    | 
|* 1 | COUNT STOPKEY    |    | 
| 2 | VIEW      |    | 
| 3 | TABLE ACCESS BY INDEX ROWID| MyTable  | 
| 4 |  INDEX FULL SCAN DESCENDING| SYS_C008809 | 

Predicate Information (identified by operation id):  
---------------------------------------------------  

    1 - filter(ROWNUM<50000000)       

Nó là không bình thường với tôi rằng Oracle đang tạo ra kế hoạch thực hiện khác nhau cho hai truy vấn này mà về cơ bản trở cùng tập kết quả.

Sửa 3: Cảm nhận Re Amoq của:

Oracle không biết 50M đó là lớn hơn số hàng. Chắc chắn, nó có thống kê, nhưng chúng có thể là cũ và sai - và Oracle sẽ không bao giờ cho phép chính nó cung cấp kết quả không chính xác chỉ vì số liệu thống kê là sai.

Bạn có chắc chắn không? Trong các phiên bản Oracle lên đến 9 nó được khuyến khích để làm mới số liệu thống kê theo cách thủ công theo thời gian. Kể từ phiên bản 10 Oracle tự động cập nhật số liệu thống kê. Việc sử dụng dữ liệu thống kê là gì nếu Oracle không sử dụng nó để tối ưu hóa truy vấn?

+0

Tại sao không may là trình tự cũng được sử dụng cho các bảng khác? Nó không quan trọng đối với truy vấn để lấy ra các bản ghi được chèn n mới nhất bởi vì một chuỗi không bao giờ được kiểm duyệt để không bị mất khoảng cách bởi Oracle. Vì vậy, bạn không thể làm một đơn giản, nơi id giữa max-n và max anyway. – tuinstoel

+0

Truy vấn của bạn chọn * tất cả * cột cho * tất cả * hàng. Tại sao bạn ngạc nhiên rằng Oracle thực hiện quét bảng ful? Làm cách nào khác để nhận dữ liệu để đáp ứng truy vấn đó? – APC

+0

Oracle không * biết * rằng 50M lớn hơn số hàng. Chắc chắn, nó có số liệu thống kê, nhưng chúng có thể cũ và sai - và Oracle sẽ * không bao giờ * cho phép bản thân cung cấp kết quả không chính xác chỉ vì số liệu thống kê sai. –

Trả lời

15

Sử dụng ROWNUM:

select 
    * 
from 
    (
    select 
     * 
    from 
     foo 
    order by 
     bork 
    ) x 
where 
    ROWNUM <= n 

Lưu ý rằng rownum được áp dụng trước sắp xếp cho một subquery, đó là lý do tại sao bạn cần hai truy vấn lồng nhau, nếu không bạn sẽ chỉ nhận được n hàng ngẫu nhiên.

+0

chính xác ........ –

+0

Điều này ngụ ý rằng bork có thể sắp xếp ... Có tương thích với OP không? Nó rất tốt có thể được nhưng nếu như vậy nó sẽ là lẻ rằng OP sẽ hỏi một câu hỏi đơn giản như vậy. –

+1

Nếu chúng tôi lấy bork là khóa chính được tạo thứ tự mà OP đã đề cập và giả định nó tăng lên một cách đơn điệu, thì truy vấn này sẽ hoạt động. – Dan

4

Nó có được xem nhiều lần hơn số lần cập nhật không? Làm thế nào về việc giữ một bảng ID khác của các hàng được chèn vào N cuối cùng (sử dụng trình kích hoạt để xóa ID nhỏ nhất khỏi bảng này và thêm một hàng mới có chèn hiện tại).

Bây giờ bạn có bảng ghi lại ID của N hàng được chèn vào cuối cùng. Bất cứ lúc nào bạn muốn N, chỉ cần tham gia nó vào bảng chính. Nếu N thay đổi, hãy chọn tối đa nó có thể và sau đó lọc nó sau ... tất nhiên bạn có thể thấy nó không quá nhanh cho ứng dụng của bạn (bảo trì bảng này có thể phủ nhận bất kỳ lợi ích nào)

3

Điều này có thể giúp bạn nếu bạn không biết tên của các trường hoặc bất cứ điều gì khác hơn là tên bảng ....

select * from (
    select * from(
    select rownum r,student.* from student where rownum<=(
     select max(rownum) from student 
    ) 
) order by r desc 
) where r<=10; 
3

Hãy thử làm một index_desc gợi ý

select /*+ index_desc(MyTable,<PK_index>) */ * from MyTable order by primarykeyfield desc 
3

trong trường hợp bạn không có một nghiêm gia tăng lĩnh vực, bạn cũng có thể sử dụng ORA_ROWSCN (số thay đổi hệ thống) như là một xấp xỉ của thi S.

select * from (select * from student order by ORA_ROWSCN desc) where rownum<10 

Thận trọng: điều này không chính xác, vì Oracle chỉ ghi một SCN cho mỗi khối, không phải mỗi hàng. Ngoài ra nó có vẻ như để làm một bảng đầy đủ quét - có lẽ oracle không đủ thông minh để tối ưu hóa loại hình này. Vì vậy, điều này có thể không phải là một ý tưởng tốt cho việc sử dụng sản xuất.

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