где rownum = 1 время запроса в Oracle - PullRequest
2 голосов
/ 15 марта 2011

Я пытаюсь выполнить запрос, подобный

select * from tableName where rownum=1

Этот запрос в основном предназначен для извлечения имен столбцов таблицы. В таблице содержится более миллиона записей. Когда я ставлю вышеуказанное условие, егозанимает столько времени, чтобы получить первый ряд. Есть ли альтернатива, чтобы получить первый ряд.

Ответы [ 6 ]

12 голосов
/ 15 марта 2011

На этот вопрос уже был дан ответ, я просто предоставлю объяснение, почему иногда фильтр ROWNUM = 1 или ROWNUM <= 1 может привести к длительному времени отклика.на одной таблице), оптимизатор произведет ПОЛНОЕ СКАНИРОВАНИЕ с COUNT STOPKEY.Это означает, что Oracle начнет читать строки, пока не встретит первые N строк (здесь N = 1).При полном сканировании считываются блоки от первой степени до верхней отметки.Oracle не может определить, какие блоки содержат строки, а какие нет, поэтому все блоки будут считываться до тех пор, пока не будет найдено N строк.Если первые блоки пусты, это может привести ко многим прочтениям. </p>

Примите во внимание следующее:

SQL> /* rows will take a lot of space because of the CHAR column */
SQL> create table example (id number, fill char(2000));

Table created

SQL> insert into example 
  2     select rownum, 'x' from all_objects where rownum <= 100000;

100000 rows inserted

SQL> commit;

Commit complete

SQL> delete from example where id <= 99000;

99000 rows deleted

SQL> set timing on
SQL> set autotrace traceonly
SQL> select * from example where rownum = 1;

Elapsed: 00:00:05.01

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=7 Card=1 Bytes=2015)    
   1    0   COUNT (STOPKEY)
   2    1     TABLE ACCESS (FULL) OF 'EXAMPLE' (TABLE) (Cost=7 Card=1588 [..])

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

Как вы можете видеть, количество последовательных запросов очень велико (для одной строки).Такая ситуация может возникнуть в некоторых случаях, когда, например, вы вставляете строки с подсказкой /*+APPEND*/ (таким образом, выше верхней отметки), а также периодически удаляете самые старые строки, в результате чего в началесегмент.

4 голосов
/ 15 марта 2011

Попробуйте это:

select * from tableName where rownum<=1

Есть некоторые странные ошибки ROWNUM, иногда, если немного изменить запрос, это исправит это. Я видел это раньше, но я не могу воспроизвести это.

Вот некоторые обсуждения похожих вопросов: http://jonathanlewis.wordpress.com/2008/03/09/cursor_sharing/ и http://forums.oracle.com/forums/thread.jspa?threadID=946740&tstart=1

4 голосов
/ 15 марта 2011

Конечно, у Oracle есть таблицы метаданных, которые вы можете использовать для получения имен столбцов, например, таблица sysibm.syscolumns в DB2?

И после быстрого веб-поиска это выглядит так: см. ALL_TAB_COLUMNS.

Я бы использовал их вместо того, чтобы перейти к реальной таблице, что-то вроде (не проверено):

SELECT   COLUMN_NAME
FROM     ALL_TAB_COLUMNS
WHERE    TABLE_NAME = "MYTABLE"
ORDER BY COLUMN_NAME;

Если вы одержимы желанием выяснить, почему ваш запрос медленный, вам следует вернуться к стандартному методу: попросить вашу СУБД объяснить план выполнения запроса для вас. Для Oracle см. Раздел 9 этого документа .

В Ask Tom - Oracle есть разговор, который, кажется, предполагает, что номера строк создаются после фазы выбора, что может означать, что запрос все равно извлекает все строки. explain, вероятно, поможет установить это. Если он содержит FULL без COUNT STOPKEY, то это может объяснить производительность.

Кроме того, мои знания специфики Oracle уменьшаются, и вам придется анализировать explain дальше.

2 голосов
/ 15 марта 2011

Ваш запрос выполняет полное сканирование таблицы, а затем возвращает первую строку.

Попробуйте

SELECT * FROM table WHERE primary_key = primary_key_value;

Первая строка, особенно в части ROWNUM, определяется Oracle произвольно. Это может отличаться от запроса к запросу, если вы не предоставите предложение ORDER BY.

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

1 голос
/ 15 марта 2011

Я думаю, что вы немного упускаете понятие ROWNUM - согласно документации Oracle: "ROWNUM - это псевдостолбец, который возвращает позицию строки в наборе результатов. ROWNUM оценивается ПОСЛЕ того, как записи выбираются из базы данныхи ДО выполнения предложения ORDER BY. " Таким образом, он возвращает ЛЮБУЮ строку, которая учитывает # 1 в наборе результатов, который в вашем случае будет содержать 1M строк.

Возможно, вы захотите проверить ROWIDпсевдостолбец: http://psoug.org/reference/pseudocols.html

0 голосов
/ 18 марта 2017

У меня недавно была та же проблема, которую вы описываете: я хочу, чтобы одна строка из очень большой таблицы была бы быстрой, грязной, простой самоанализ, и один "где rownum = 1" ведет себя очень плохо.Ниже приведено лекарство, которое сработало для меня.

Выберите max () первого члена некоторого индекса, а затем используйте его, чтобы выбрать небольшую долю всех строк с "rownum = 1".Предположим, что у моей таблицы есть некоторый индекс числового идентификатора группы, и сравните это:

 select * from my_table where rownum = 1;
 -- Elapsed: 00:00:23.69

с этим:

 select * from my_table where rownum = 1
    and group_id = (select max(group_id) from my_table);
 -- Elapsed: 00:00:00.01
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...