2009-07-09 3 views
1

Oracle 10gの数値型列の最小値または最大値に関する統計を取得できますか? LOW_VALUE列とHIGH_VALUE列を持つテーブルUSER_TAB_COL_STATISTICSが見つかりましたが、それらが私が探している値であるかどうかはわかりません。Oracle 10g:MIN/MAX列の値の見積もり

これらの統計情報をDBSに問い合わせる効率的な方法を見つける必要があります。通常のMIN(a)およびMAX(a)クエリを使用すると、大きなテーブルでは処理が遅くなります。

ありがとうございます。

答えて

3

はい、LOW_VALUEとHIGH_VALUEはあなたのコラムが、での最小値と最大値教えてくれます:意味はすぐに明らかにされませんので、

彼らはRAWとして格納されている
  • (32)の列を
  • (明示的にそれらを使用する前に、統計情報を収集していない限り)彼らは

あなたは、インデックスのカラムその後、MIN(a)とMAXの場合は統計がテーブルのために収集された最後の時間のようになりますので、正確ではないかもしれません( a)ショーT1は50000行があり、OBJECT_IDにインデックスが作成され、この例のように非常に高速であるULD:あなたの代わりにMINのMAXを選択した場合

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 

結果は同じです。あなたは、単一の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 

私は決定的にそれを証明していないが、これは、それらを個別に取得する方がよいことを示唆しています。

+0

:-)かなり多くのことができますおかげでトニーを。 – Kage

+0

@トニー、minとmaxの両方をクエリすると、説明計画は何ですか?これは途中でのテストです。 – Theo

+0

@トニー:うわー、大丈夫。私はその後、私の実装を変更する必要があります。私は同時に両方を取り戻そうとしました...私はあなたに投票しますが、私はまだそれを行うことはできませんが、私の象徴的な投票を受け入れてください:-)。 – Kage

2

1234までの1から番号を含むテーブルを持つ例:

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. 

しかし、注意してください:更新は統計が収集された時間と、クエリが実行された時間の間で起こったときの数字は不正確になることがあります。

よろしく、 ロブ。

+0

おかげでRob、それも助けて! Mmh、2つの方法(MIN/MAX vs. gather_table_stats)のどちらがより効率的であるかは、どのようにして判断するのですか? – Kage

+0

新しいデータが1週間に1回のみ受信され、毎分/毎分の値が毎分数回選択される状況では、gather_table_statsだけを検討します。 データの変更頻度が高い場合は、インデックスを使用してください。 – jva

+0

指標は統計のように更新する必要がありますか?そうではありませんか?どちらが当てはまるかわからない。 私が開発しているデータベースミドルウェアは、かなり一般的でなければならず、データの到着頻度を事前に知る必要はありません。 MIN/MAXメソッドのメリットの1つは、SQLベースのDBSで動作するはずですが、収集統計メソッドはOracleのみです。私は現在ミドルウェアの下でOracle 10を使用していますが、システムは長期的にはすべてのDBSで動作するはずです。現時点では、私はOracleに最適なソリューションしか必要としません。 – Kage

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"アプローチよりもこのアプローチの利点は、統計情報を生成するためにanalyticsがこのようなクエリを実行するということです。このようにすると、全体。

+0

これも素晴らしいですね!良いことは、管理者がテーブルの統計情報を定期的に作成して更新するのに賢明であることに頼る必要がないことです。感謝ジェフリー! – Kage

+0

これに関する別の質問:これを小さなテーブルで実行しようとしましたが、割合が低すぎると結果が得られないようです。 – Kage

+0

はい、そうでしょう。 SAMPLE(50)は、コインが各行に対して反転されることを意味します。頭が上がると、行が返されます。尾が上がると、行は無視されます。割合が低いほど、行が選択されない可能性が高くなります。表の期待される行数に従ってSAMPLEパーセンテージを調整する必要があります。 –

0

私の場合、興味のある列はTIMESTAMPの型を持っていて、それはUTL_RAW.CAST_TO_TIMESTAMPの機能のようではありません。

それはTIMESTAMPへのOracle RAWタイプを変換するhttp://www.oaktable.net/content/convert-rawhex-timestamp-0からトリックを使用することを助けた:

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' 
) 
関連する問題