2009-12-01 5 views
6

Таблица содержит первичный первичный ключ к суррогатной генерации из последовательности. К сожалению, эта последовательность используется для генерации ключей для некоторых других таблиц (я не проектировал ее, и я не могу ее изменить).Выберите `n` последние вставленные записи в таблицу - оракул

Что является самым быстрым способом выбора последнего n вставленных записей в Oracle, упорядоченных по id в порядке убывания (последний вставлен сверху)?

n некоторое относительно небольшое число - количество записей, отображаемых на странице - вероятно, не больше, чем 50.

Таблица теперь имеет 30.000.000 записей с 10-15 тысячами новых записей ежедневно.

База данных - это Oracle 10g.

Edit:
В ответ на один комментарий: Этот вопрос был мотивирован план выполнения для запроса:

select * from MyTable order by primarykeyfield desc 

план выполнения был:

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

Я был удивлен, что Oracle хочет выполнить полное сканирование таблицы и сортировку, когда она имеет индекс в поле сортировки.

Запрос от принятого ответа использует индекс и позволяет сортировать сортировку.

Редакция 2:
Re. Комментарий APC: Сортировка была частью, которая меня удивила. Я ожидал, что Oracle будет использовать индекс для извлечения строк в ожидаемом порядке. План выполнения для запроса:

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

использует индекс вместо полного доступа к таблице и сортировки (уведомление условие rownum < 50.000.000 - это намного больше, чем число записей в таблице и Oracle знает, что он должен получить все записи из таблицы). Этот запрос возвращает все строки в качестве первого запроса, но следующий план выполнения:

| 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)       

Это было необычно для меня, что Oracle создает различные планы выполнения для этих двух запросов, которые по существу возвращают одинаковый набор результатов.

Редактировать 3: комментарий Re Amoq в:

Oracle не знает, что 50М больше, чем число строк. Конечно, у него есть статистика, но они могут быть старыми и неправильными - и Oracle никогда бы не позволил себе поставить неверный результат только потому, что статистика неверна.

Уверены ли вы? В версиях Oracle до 9 рекомендуется время от времени обновлять статистику вручную. Начиная с версии 10 Oracle автоматически обновляет статистику. Что такое использование статистических данных, если Oracle не использует его для оптимизации запросов?

+0

Почему прискорбно, что последовательность также используется для других таблиц? Не имеет значения, чтобы запрос извлекал последние n вставленных записей, потому что Oracle никогда не может быть безразличной. Таким образом, вы не можете сделать простой, где id между max-n и max в любом случае. – tuinstoel

+0

Ваш запрос выбирает * все * столбцы для * всех * строк. Почему вы удивлены тем, что Oracle делает полное сканирование таблицы? Как еще он получит данные для удовлетворения этого запроса? – APC

+0

Oracle не знает *, что 50M больше числа строк. Конечно, у него есть статистика, но они могут быть старыми и неправильными - и Oracle никогда не позволит себе поставить неверный результат только потому, что статистика неверна. –

ответ

15

Использование ROWNUM:

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

Обратите внимание, что rownum применяется перед тем сортировки для подзапроса, поэтому вам нужно два вложенных запросов, в противном случае вы просто получите n случайные строки.

+0

точно ........ –

+0

Это означает, что bork сортируется ... Это совместимо с OP? Это очень хорошо, но если так было бы странно, что ОП задавал бы такой простой вопрос. –

+1

Если мы возьмем bork, чтобы быть первичным ключом, сгенерированным в последовательности, указанным OP, и если предположить, что он монотонно увеличивается, тогда этот запрос будет работать. – Dan

4

Будет ли он просмотрен еще много раз, чем он обновляется? Как насчет сохранения другой таблицы идентификаторов последних N вставленных строк (используйте триггер для удаления наименьшего идентификатора из этой таблицы и добавления новой строки с вставленным в текущий момент).

Теперь у вас есть таблица, в которой записаны идентификаторы последних N вставленных строк. Каждый раз, когда вы хотите N, просто присоедините его к основной таблице. Если N изменяется, выберите максимальное значение, которое может быть, а затем отфильтруйте его после ... конечно, вы можете найти его не так быстро для своего приложения (обслуживание этой таблицы может отрицать любое увеличение производительности)

3

Это может помочь вам если вы не знаете имя поля или что-либо, кроме имени таблицы ....

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

Попробуйте делать index_desc намек

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

В тех случаях, когда вы не имеете строго увеличивая поле, вы также можете использовать ORA_ROWSCN (номер смены системы) в качестве приближения s.

Предупреждение: это не точно, поскольку Oracle записывает только один SCN для каждого блока, а не для каждой строки. Также, похоже, полный сканирование таблицы - возможно, оракул недостаточно умен, чтобы оптимизировать этот вид сортировки. Таким образом, это может быть не очень хорошая идея для использования в производстве.

Смежные вопросы