2012-05-23 2 views
3

С моей точки зрения, rownum применяется ко всему набору результатов после того, как он был запрошен. Это означает, что если я хочу ограничить результаты с помощью rownum, он все равно будет запрашивать все поначалу. У меня есть таблица пользователей, которая содержит более ста тысяч записей. Я также разрабатываю сайт, который ищет эту таблицу, возвращая результирующий набор. К сожалению, реквестер хочет, чтобы я включил возможность поиска на JUST фамилию.Oracle rownum <[n] альтернативы? Понимание?

Представьте себе о «джонах», «белых», «коричневых», которые могут вернуться. Я хотел бы вернуть не более 200 записей, есть ли лучший способ сделать это вместо использования rownum? Мое понимание, когда rownum применяется правильно?

ответ

8
SELECT * 
FROM (
     SELECT * 
     FROM mytable 
     WHERE lastname = 'Jones' 
     ORDER BY 
       id 
     ) 
WHERE rownum <= 200 

или

SELECT * 
FROM (
     SELECT *, ROW_NUMBER() OVER (ORDER BY id) rn 
     FROM mytable 
     WHERE lastname = 'Jones' 
     ) 
WHERE rn <= 200 

Последний был медленнее 9i но работает точно так же в 10g+.

Из моего понимания, ROWNUM применяется ко всему результирующего набора после того, как она была опрошена

порядка № rownum применяется как только каждой записи, удовлетворяющей пункт WHERE забирается (но прежде чем они заказываются).

Собственно, вложенный запрос требуется здесь, потому что ROWNUM оценивается до ORDER BY.

И ROWNUM, и ROW_NUMBER() могут быть оптимизированы. Если у вас есть индекс на (lastname, id), запрос будет использовать индекс и останавливаться после возвращения 200-й записи (в плане вы увидите COUNT(STOPKEY)).

Также существует общая оговорка с ROWNUM и пейджингом. Этот запрос:

SELECT * 
FROM (
     SELECT * 
     FROM mytable 
     WHERE lastname = 'Jones' 
     ORDER BY 
       id 
     ) 
WHERE rownum BETWEEN 201 AND 400 

никогда ничего не вернется, потому что ROWNUM само по себе является частью состояния WHERE. Двигатель просто не может вернуть первую строку, потому что он будет иметь ROWNUM = 1, который не удовлетворяет пункту WHERE.

Чтобы обойти эту проблему, вам придется дважды гнездо запрос:

SELECT * 
FROM (
     SELECT q.*, ROWNUM AS rn 
     FROM (
       SELECT * 
       FROM mytable 
       WHERE lastname = 'Jones' 
       ORDER BY 
         id 
       ) q 
     ) 
WHERE rn BETWEEN 201 AND 400 

Это будет оптимизирован для COUNT(STOPKEY) тоже.

+0

Благодарим за отзыв. –

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