Oracle 10g: оценка значения столбца MIN / MAX - PullRequest
1 голос
/ 09 июля 2009

возможно ли получить статистику о минимальном или максимальном значении числового столбца в Oracle 10g? Я нашел таблицу USER_TAB_COL_STATISTICS, в которой есть столбцы LOW_VALUE и HIGH_VALUE, но я не уверен, являются ли эти значения искомыми.

Мне нужно найти эффективный способ запросить у DBS эти статистические данные. Использование обычных запросов MIN (a) и MAX (a) было бы слишком медленным для больших таблиц.

Заранее спасибо.

Ответы [ 4 ]

3 голосов
/ 09 июля 2009

Да, LOW_VALUE и HIGH_VALUE сообщат вам минимальное и максимальное значения в столбце , но :

  • они хранятся в виде столбцов RAW (32), поэтому значение не будет сразу видно
  • они будут на момент последнего сбора статистики для таблицы, поэтому могут быть неточными (если вы явно не собираете статистику перед их использованием)

Если вы индексируете столбец, то MIN (a) и MAX (a) должны быть очень быстрыми, как в этом примере, где T1 имеет 50000 строк и индексируется по OBJECT_ID:

SQL> select min(object_id) from t1;

MIN(OBJECT_ID)
--------------
           100

------------------------------------------------------------------------------------
| Id  | Operation                  | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |       |     1 |     5 |     2   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE            |       |     1 |     5 |            |          |
|   2 |   INDEX FULL SCAN (MIN/MAX)| T1_ID | 53191 |   259K|     2   (0)| 00:00:01 |
------------------------------------------------------------------------------------

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

Результат будет таким же, если вы выберете MAX вместо MIN. Однако если вы выберете MIN и MAX в одном операторе select, результат будет другим:

SQL> select min(object_id), max(object_id) from t1;

MIN(OBJECT_ID) MAX(OBJECT_ID)
-------------- --------------
           100          72809


-------------------------------------------------------------------------------
| Id  | Operation             | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |       |     1 |     5 |    34   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE       |       |     1 |     5 |            |          |
|   2 |   INDEX FAST FULL SCAN| T1_ID | 53191 |   259K|    34   (0)| 00:00:01 |
-------------------------------------------------------------------------------


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

Это говорит о том, что может быть лучше получить их отдельно, хотя я не убедительно доказал это.

2 голосов
/ 09 июля 2009

Пример с таблицей, содержащей числа от 1 до 1234:

SQL> create table t (nr) as select level from dual connect by level <= 1234
  2  /

Tabel is aangemaakt.

SQL> select min(nr)
  2       , max(nr)
  3    from t
  4  /

   MIN(NR)    MAX(NR)
---------- ----------
         1       1234

1 rij is geselecteerd.

Если вы анализируете таблицу, столбцы low_value и high_value содержат правильные числа.

SQL> exec dbms_stats.gather_table_stats(user,'t')

PL/SQL-procedure is geslaagd.

SQL> select low_value
  2       , high_value
  3    from user_tab_columns
  4   where table_name = 'T'
  5     and column_name = 'NR'
  6  /

LOW_VALUE                                                        HIGH_VALUE
---------------------------------------------------------------- ----------------
C102                                                             C20D23

1 rij is geselecteerd.

Они необработанные, поэтому их нелегко прочитать. Использование функции utl_raw.cast_to_number делает их читабельными:

SQL> select utl_raw.cast_to_number(low_value)
  2       , utl_raw.cast_to_number(high_value)
  3    from user_tab_columns
  4   where table_name = 'T'
  5     and column_name = 'NR'
  6  /

UTL_RAW.CAST_TO_NUMBER(LOW_VALUE) UTL_RAW.CAST_TO_NUMBER(HIGH_VALUE)
--------------------------------- ----------------------------------
                                1                               1234

1 rij is geselecteerd.

Однако будьте осторожны: числа могут быть неточными, если обновления произошли между временем сбора статистики и временем выполнения запроса.

С уважением, Роб.

1 голос
/ 10 июля 2009

Другие ответы здесь (с использованием быстрого полного сканирования индекса или проверки статистики user_tab_columns) превосходны.

Вот еще один метод, который может подойти - если вас интересует только приблизительная оценка, вы можете воспользоваться предложением SAMPLE (и отрегулировать размер выборки вверх или вниз в зависимости от того, насколько она вам нужна):

SELECT max(value), min(value) FROM t SAMPLE(1);

Это займет 1% выборки из таблицы. Обычно при каждом запуске он выбирает разные строки, поэтому не ожидайте, что результаты будут одинаковыми при запуске. Если вы хотите, чтобы он работал быстрее, вы можете использовать меньшие размеры выборки, например, SAMPLE(0.01), или, если вы хотите взять половину таблицы, SAMPLE(50).

Преимущество этого подхода по сравнению с подходом "анализ, затем-запрос-пользователя-вкладки" заключается в том, что анализ в любом случае выполняет запросы, подобные этим, для генерации статистики - поэтому выполнение этого способа может означать меньше работы в целом .

0 голосов
/ 29 сентября 2015

В моем случае интересующий столбец имеет тип TIMESTAMP и, похоже, функции UTL_RAW.CAST_TO_TIMESTAMP нет.

Это помогло использовать трюк из http://www.oaktable.net/content/convert-rawhex-timestamp-0 для преобразования типа Oracle RAW в TIMESTAMP:

select to_timestamp(
        to_char( to_number( substr( p_str, 1, 2 ), 'xx' ) - 100, 'fm00' ) ||
        to_char( to_number( substr( p_str, 3, 2 ), 'xx' ) - 100, 'fm00' ) ||
        to_char( to_number( substr( p_str, 5, 2 ), 'xx' ), 'fm00' ) ||
        to_char( to_number( substr( p_str, 7, 2 ), 'xx' ), 'fm00' ) ||
        to_char( to_number( substr( p_str,9, 2 ), 'xx' )-1, 'fm00' ) ||
        to_char( to_number( substr( p_str,11, 2 ), 'xx' )-1, 'fm00' ) ||
        to_char( to_number( substr( p_str,13, 2 ), 'xx' )-1, 'fm00' ), 'yyyymmddhh24miss' )
from (
select low_value p_str from user_tab_columns
   where table_name = 'MESSAGE' and column_name = 'TS'
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...