是否可以检索有关Oracle 10g中数字列的最小值或最大值的统计信息?我发现表USER_TAB_COL_STATISTICS有一个LOW_VALUE和HIGH_VALUE列,但我不确定这些是否是我要查找的值。
我需要找到一种有效的方式向DBS询问这些统计数据。使用常规MIN(a)和MAX(a)查询对于大型表来说太慢了。
提前致谢。
答案 0 :(得分:3)
是的,LOW_VALUE和HIGH_VALUE会告诉您列中的最小值和最大值,但:
如果您为列编制索引,那么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'
)