2015-02-11 6 views
2

При подготовке к пакетному процессу мне нужно разбить группы записей для запуска параллельных потоков задания. Эти записи поступают из таблицы, в которой потенциально могут быть миллионы строк. Моя цель - равномерно разбить эти записи (по первичному ключу) на (приблизительно) даже куски, которые затем могут обрабатываться параллельно. Я хочу динамически выбирать размер куска. Также можно отметить, что могут быть пробелы в последовательности первичных ключей.Результирующий набор разделов SQL в куски

Другими словами, учитывая эту таблицу, с предикатом, обозначающим количество блоков и набора результатов предоставления первой и последней последовательности фрагмента:

seq name | 
-------|--------| 
1  | john | 
2  | joe | 
3  | joe | 
4  | joe | 
5  | joe | 
567 | kent | 
568 | katie | 
20000 | sue | 
200016 | jill | 
200027 | bill | 

Я хотел бы получить обратно следующие результаты, где (число-кусках) -> (первый, последний SEQ-сл):

(2) -> (1,5),(567,20027) 
(5) -> (1,2),(3,4),(5,567),(568,20000),(200016,200027) 

Или, как набор результатов, что-то вроде этого (когда просят 5 порций):

 
first_seq last_seq 
-----------|----------| 
    1  | 2  | 
    3  | 4  | 
    5  | 567  | 
    568  | 200000 | 
    20016 | 200027 | 

Я предполагаю, что какая-то функция окна здесь в порядке, но я не знаю, как это решить. Может ли кто-нибудь помочь мне с запросом?

функция
+0

вы можете добавить ожидаемый результат в виде таблицы –

+0

, что вы звоните «chunk- размер ", по-видимому, является количеством кусков, которые вы хотите, верно? (Обычно я читал «размер блока» как количество элементов, которые должны появляться в каждом фрагменте.) –

+0

Будет ли это использоваться с SQLServer или MySQL? –

ответ

1

Думайте, что это должно хорошо работать с большинством систем БД.

1) Положите chunk в список полях, чтобы быть более подробным; то же самое для order by

2) разделили последовательность вверх в 10 куски с ... (10/(num_rows + ...

select MIN(seq) as first_seq, MAX(seq) as last_seq, chunk from 
     /*- Basic grouping formula pseudo: #row_chunk_number = round-up((#total_num_chunks/#total_num_rows) x #current_row_num) 
      - The +0.0 is to convert field values to floats 
      - floor() + 1 means the same as rounding up ... and im not sure if ceil() exists on all DB systems. 
     */ 
     (select seq, floor(((10/(num_rows + 0.0)) + 0.0) * (row_num + 0.0)) + 1 as chunk from 
     (select 
      seq, 
      /*`row_num` is the row number in the sequence range - achieved by iteratively counting all sequences smaller than current (assuming seq is unique and numeric).*/ 
      (select COUNT(*) from table1 as b where b.seq < a.seq) as row_num, 
      /*`num_rows` is the number of rows in the sequence range - added to inner query to prevent cluttering the actual math calc in the outer query (same performance).*/ 
      (select COUNT(*) from table1) as num_rows 
     /*dat1 is a derived table of seq (id), num_rows (total number rows) and row_num (row number)*/ 
     from table1 as a) as dat) as dat1 
group by chunk 
order by chunk 
+0

Это работает!Не могли бы вы добавить некоторые комментарии к SQL, объясняя логику? Некоторые из них немного неинтуитивны (но, возможно, это только я). – sparty02

+0

Есть ли что-то конкретное, что кажется неясным? –

+0

Добавили несколько комментариев к моему решению. Может быть, это полезно для моего ответа? –

2

NTILE может работать для вас в Oracle (я не уверен, DB2):

SELECT seq, ntile(2) over (order by seq) chunk_num 
    FROM my_table 

(где 2 это количество порций)

Или, чтобы получить результаты в макет вы описали:

SELECT chunk_num, MIN(seq), MAX(seq) FROM (
    SELECT seq, ntile(2) over (order by seq) chunk_num 
    FROM my_tab 
) 
    GROUP BY chunk_num 

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

+0

Помню, как эта функция использовалась много лет назад, она полностью забыла об этом. Хороший ответ. –

+0

Это определенно в соответствии с тем, что я ищу ... если это действительно поддерживается DB2. Основываясь на предположении использования NTILE, я нашел [этот камень] (http://wloclawek.wsinf.edu.pl/~kzebrows/SQL/OReilly.SQL.Cookbook.Dec.2005/0596009763/sqlckbk-CHP-12- SECT-8.html) с помощью быстрого поиска. Я проверю это завтра, когда у меня снова появится доступ к моей БД и посмотрю, работает ли он. Спасибо @DaveCosta – sparty02

+0

К сожалению, это не работает на DB2, поэтому, хотя это было бы моим предпочтительным решением, решение @ ChrisduPreez является агностиком базы данных. – sparty02

Смежные вопросы