Oracle, как разделить данные и получать записи на каждые 10% - PullRequest
1 голос
/ 05 августа 2011

У меня есть гигантская таблица с миллиардами записей, подобных этой:

ID   |  H  |  N   |  Q  | other
-----+-----+------+-----+--------
AAAA |  0  |  7   |  Y  | ...
BBBB |  1  |  5   |  Y  | ...
CCCC |  0  |  11  |  N  | ...
DDDD |  3  |  123 |  N  | ...
EEEE |  6  |  4   |  Y  | ...

Эти четыре столбца являются частью индекса.Я хочу создать запрос, который даст мне 1-ю строку, за которой следует строка 10%, 20%, 30%, 40%, ... так что запрос всегда даст мне 10 строк, независимо от того, насколько великтаблица (до тех пор, пока # row> = 10).

Возможно ли это даже с SQL?Если так, как бы я это сделал?Какие у него характеристики производительности?

Ответы [ 2 ]

3 голосов
/ 05 августа 2011

Один вариант будет

SELECT id,
       h,
       n,
       q
  FROM (
    SELECT id, 
           h, 
           n, 
           q,
           row_number() over (partition by decile order by id, n) rn
      FROM (
        SELECT id, 
               h, 
               n, 
               q,
               ntile(10) over (order by id, n) decile
          FROM your_table
            )
        )
   WHERE rn = 1

Вероятно, есть более эффективный подход, использующий PERCENTILE_DISC или CUME_DIST, который сейчас мне не подходит Но это должно сработать.

0 голосов
/ 09 августа 2011

Вы можете использовать гистограмму, чтобы получить эту информацию.Огромным недостатком является то, что результаты будут только приблизительными, и очень сложно сказать, насколько приблизительными они будут.И вам нужно собрать статистику таблицы, чтобы обновить результаты, но вы, вероятно, уже делаете это.С положительной стороны, запрос на получение результатов будет очень быстрым.И использование статистики вместо запроса будет , поэтому круто.

Вот краткая демонстрация:

--Create a table with the IDs AA - ZZ.
create table test(id varchar2(100), h number, n number, q varchar2(100)
    ,other varchar2(100));

insert into test 
select letter1||letter2 letters, row_number() over (order by letter1||letter2), 1, 1, 1
from
    (select chr(65+level-1) letter1 from dual connect by level <= 26) letters1
    cross join
    (select chr(65+level-1) letter2 from dual connect by level <= 26) letters2
;
commit;

--Gather stats, create a histogram with 11 buckets (we'll only use the first 10)
begin
    dbms_stats.gather_table_stats(user, 'TEST', cascade=>true,
        method_opt=>'FOR ALL COLUMNS SIZE AUTO, FOR COLUMNS SIZE 10 ID');
end;
/

--Getting the values from user_histograms is kinda tricky, especially for varchars.
--There are problems with rounding, so some of the values may not actually exist.
--
--This query is from Jonathan Lewis:
-- http://jonathanlewis.wordpress.com/2010/10/05/frequency-histogram-4/
select
        endpoint_number,
        endpoint_number - nvl(prev_endpoint,0)  frequency,
        hex_val,
        chr(to_number(substr(hex_val, 2,2),'XX')) ||
        chr(to_number(substr(hex_val, 4,2),'XX')) ||
        chr(to_number(substr(hex_val, 6,2),'XX')) ||
        chr(to_number(substr(hex_val, 8,2),'XX')) ||
        chr(to_number(substr(hex_val,10,2),'XX')) ||
        chr(to_number(substr(hex_val,12,2),'XX')),
        endpoint_actual_value
from    (
        select
                endpoint_number,
                lag(endpoint_number,1) over(
                        order by endpoint_number
                )                                                       prev_endpoint,
                to_char(endpoint_value,'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')hex_val,
                endpoint_actual_value
        from
                user_histograms
        where   table_name = 'TEST'
        and     column_name = 'ID'
        )
where
        endpoint_number < 10
order by
        endpoint_number
;

Вот сравнение гистограммырезультаты с реальными результатами запроса @Justin Cave:

Histogram:    Real results:
A@            AA
CP            CQ
FF            FG
HV            HW
KL            KM
NB            NC
PR            PS
SG            SH
UU            UW
XK            XL
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...