Oracle 10g:MIN / MAX列值估计

时间:2009-07-09 09:35:18

标签: oracle oracle10g

是否可以检索有关Oracle 10g中数字列的最小值或最大值的统计信息?我发现表USER_TAB_COL_STATISTICS有一个LOW_VALUE和HIGH_VALUE列,但我不确定这些是否是我要查找的值。

我需要找到一种有效的方式向DBS询问这些统计数据。使用常规MIN(a)和MAX(a)查询对于大型表来说太慢了。

提前致谢。

4 个答案:

答案 0 :(得分:3)

是的,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,结果相同。但是,如果在单个select语句中选择MIN和MAX,结果会有所不同:

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

这表明将它们单独分开可能会更好,但我还没有最终证明这一点。

答案 1 :(得分:2)

包含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.

但是,请注意:在收集统计信息和查询运行的时间之间进行更新时,数字可能不准确。

此致 罗布。

答案 2 :(得分:1)

此处的其他答案(使用索引快速全扫描;或检查user_tab_columns统计信息)非常好。

这是另一种可能适合的方法 - 如果您只对粗略估计感兴趣,可以使用SAMPLE子句(根据您需要的准确度来调整样本大小):

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

这需要从表中获得1%的样本。它通常会在每次运行时对不同的行进行采样,因此不要期望结果在运行之间是相同的。如果您希望它运行得更快,您可以使用较低的样本量,例如SAMPLE(0.01),或者如果您想对表格的一半进行抽样,SAMPLE(50)

这种方法优于“analyze,then-query-user-tab-cols”方法的优势在于,无论如何分析都会运行这样的查询以生成统计信息 - 这样做这样做可能意味着整体工作量减少

答案 3 :(得分:0)

在我的情况下,感兴趣的列具有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'
)