Oracle: Как вернуть только частичный результат? - PullRequest
1 голос
/ 03 марта 2009

Я использую базу данных Oracle.

В моем запросе выбрано 100 строк. Если я хочу отфильтровать строки между rownum 50 и 60, что будет запрос?

SELECT EMPLID, EFFDT, ACTION, ACTION_REASON 
from JOB where emplid ='12345'

Ответы [ 4 ]

8 голосов
/ 03 марта 2009

Поскольку я сделал сравнение Чеда и Ника подходов, чтобы прокомментировать ответ Ника, я решил опубликовать свои выводы здесь. Я использовал пакет runstats Тома Кайта, чтобы сравнить их с этим сценарием:

begin
   runstats_pkg.rs_start('Chad');
   for i in 1..10000 loop
     for r in (
      SELECT EMPLID,EFFDT,ACTION,ACTION_REASON
      FROM (SELECT ROWNUM rnum, EMPLID,EFFDT,ACTION,ACTION_REASON
            FROM (SELECT EMPLID,EFFDT,ACTION,ACTION_REASON
                  FROM JOB
                  WHERE emplid = '12345')
            WHERE rownum <= 60
      )
      WHERE rnum >= 50
      ) loop
        null;
      end loop;
   end loop;
   runstats_pkg.rs_middle('Nick');
   for i in 1..10000 loop
     for r in (
      select EMPLID, EFFDT, ACTION, ACTION_REASON
      from
      (
      SELECT EMPLID, EFFDT, ACTION, ACTION_REASON, row_number() over (order by emplid) rn
      from JOB where emplid ='12345'
      )
      where rn between 50 and 60
      ) loop
        null;
      end loop;
    end loop;
   runstats_pkg.rs_stop(0,false,false,false,false,false,false,false,false);
end;
/

Результаты:

Run1 = Chad
Run2 = Nick

*** Comparative Time Report ***
Run                                   Time (hsecs)
--------------------------------------------------
Run1                                            69
Run2                                            77

Run1 ran in 89.61% of the time of Run2
Run2 ran in 111.59% of the time of Run1

PL/SQL procedure successfully completed.

При использовании автотрассировки планы выглядят очень похоже:

SQL>           SELECT EMPLID,EFFDT,ACTION,ACTION_REASON
  2            FROM (SELECT ROWNUM rnum, EMPLID,EFFDT,ACTION,ACTION_REASON
  3                  FROM (SELECT EMPLID,EFFDT,ACTION,ACTION_REASON
  4                        FROM JOB
  5                        WHERE emplid = '12345')
  6                  WHERE rownum <= 60
  7            )
  8            WHERE rnum >= 50
  9  /

no rows selected


Execution Plan
----------------------------------------------------------

------------------------------------------------------------------------------
| Id  | Operation                     | Name    | Rows  | Bytes | Cost (%CPU)|
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |         |     1 |    41 |     3   (0)|
|*  1 |  VIEW                         |         |     1 |    41 |     3   (0)|
|*  2 |   COUNT STOPKEY               |         |       |       |            |
|   3 |    TABLE ACCESS BY INDEX ROWID| JOB     |     1 |    13 |     3   (0)|
|*  4 |     INDEX RANGE SCAN          | JOB2_PK |     1 |       |     2   (0)|
------------------------------------------------------------------------------

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

   1 - filter("RNUM">=50)
   2 - filter(ROWNUM<=60)
   4 - access("EMPLID"=12345)


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          2  consistent gets
          0  physical reads
          0  redo size
        264  bytes sent via SQL*Net to client
        231  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          0  rows processed

SQL>           select EMPLID, EFFDT, ACTION, ACTION_REASON
  2            from
  3            (
  4            SELECT EMPLID, EFFDT, ACTION, ACTION_REASON, row_number() over (order by emplid) rn
  5            from JOB where emplid ='12345'
  6            )
  7            where rn between 50 and 60
  8  /

no rows selected


Execution Plan
----------------------------------------------------------

------------------------------------------------------------------------------
| Id  | Operation                     | Name    | Rows  | Bytes | Cost (%CPU)|
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |         |     1 |    41 |     3   (0)|
|*  1 |  VIEW                         |         |     1 |    41 |     3   (0)|
|*  2 |   WINDOW NOSORT STOPKEY       |         |     1 |    17 |     3   (0)|
|   3 |    TABLE ACCESS BY INDEX ROWID| JOB     |     1 |    17 |     3   (0)|
|*  4 |     INDEX RANGE SCAN          | JOB2_PK |     1 |       |     2   (0)|
------------------------------------------------------------------------------

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

   1 - filter("RN">=50 AND "RN"<=60)
   2 - filter(ROW_NUMBER() OVER ( ORDER BY "EMPLID")<=60)
   4 - access("EMPLID"=12345)
       filter("EMPLID"=12345)


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          2  consistent gets
          0  physical reads
          0  redo size
        264  bytes sent via SQL*Net to client
        231  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          0  rows processed

Может показаться, что выбирать между двумя методами не так уж и много, хотя в моей базе данных Чад постоянно немного быстрее:

Oracle Database 10g Release 10.2.0.3.0 - 64-разрядная версия

8 голосов
/ 03 марта 2009

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

select EMPLID, EFFDT, ACTION, ACTION_REASON
from
(
SELECT EMPLID, EFFDT, ACTION, ACTION_REASON, row_number() over (order by emplid) rn
from JOB where emplid ='12345'
)
where rn between 50 and 60;

Использование функции row_number позволяет упорядочить результаты и пронумеровать их в одном запросе, а затем вам нужен только один запрос-оболочка, чтобы получить нужные вам строки.

7 голосов
/ 03 марта 2009

Это немного сложно в Oracle, я думаю, вы должны сделать что-то вроде этого:

SELECT EMPLID,EFFDT,ACTION,ACTION_REASON
FROM (SELECT ROWNUM rnum, EMPLID,EFFDT,ACTION,ACTION_REASON
      FROM (SELECT EMPLID,EFFDT,ACTION,ACTION_REASON
            FROM JOB
            WHERE emplid = '12345')
      WHERE rownum <= 60
)
WHERE rnum >= 50;
0 голосов
/ 03 марта 2009

Вы можете использовать ROWNUM (см. эту ссылку ). Если вам нужно контролировать порядок сортировки, вы можете обернуть другой запрос в свой запрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...