Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 "Секционирование" без секционирования  [new]
Деев И.
Member

Откуда: отсюда
Сообщений: 783
Наваял тут скриптик для обработки огромных непросекционированных таблиц. Идея простая - экстенты ведь чем-то напоминают секции. Можно получить значения rowid по номерам блоков и далее делать выборку по диапазону rowid. Можно при миграции данных использовать (перенос по DBLINK или для распараллеливания экспорта в 9-ке, в 10-ке datapump рулит). Может кому пригодится...
/*
---------------------------------------------------------------------------------
Описание : Скрипт может быть полезен при обработке очень больших таблиц. 
           Позволяет сделать выборку всех строк заданного экстента по rowid 
           на основе информации о номерах блоков экстента из dba_extents
---------------------------------------------------------------------------------
*/
declare
  -- параметры:  
  p_owner varchar2(30)       := 'IDEEV';   --<-- владелец
  p_object_name varchar2(30) := 'CL_DATA'; --<-- таблица
  p_extent_id number         := 0;
  -- переменные
  v_tablespace_name varchar2(30);
  v_block_size number := 8192;
  v_object_id number; 
  v_file_id number;
  v_block_id number;    -- первый блок
  v_blocks number;      -- кол-во блоков
  v_rowid_first rowid;
  v_rowid_second rowid;
begin
  -- object_id
  begin
    select o.object_id into v_object_id
      from dba_objects o
     where o.owner = p_owner 
       and o.object_name = p_object_name
       and o.object_type = 'TABLE';
  exception
    when no_data_found
    then dbms_output.put_line('Не найдена таблица '||p_owner||'.'||p_object_name);   
      return;
  end;   
  
  -- параметры экстента
  begin
    select e.file_id, e.block_id, e.blocks, e.tablespace_name
      into v_file_id, v_block_id, v_blocks, v_tablespace_name
      from dba_extents e
     where e.owner = p_owner 
       and e.segment_name = p_object_name
       and e.extent_id = p_extent_id;
  exception
    when others
    then dbms_output.put_line('Не найден экстент '||to_char(p_extent_id)||' таблицы '||p_owner||'.'||p_object_name);
      return;
  end;     
  
  -- размер блока (размер можно не выбирать, если он стандартный)
  select block_size into v_block_size
    from dba_tablespaces t
   where t.tablespace_name = v_tablespace_name;
  
  -- первый rowid
  v_rowid_first :=dbms_rowid.rowid_create(1, v_object_id, v_file_id, v_block_id, 0);
  -- последний rowid (берем номер последней строки равным размеру блока ;) )
  v_rowid_second :=dbms_rowid.rowid_create(1, v_object_id, v_file_id, v_block_id + v_blocks - 1, v_block_size);
  
  -- вывод результата
  dbms_output.put_line('------------------------------------------------------');
  dbms_output.put_line('owner     : '||p_owner );
  dbms_output.put_line('table name: '||p_object_name );
  dbms_output.put_line('extend_id: '||p_extent_id);
  dbms_output.put_line('rowid first: '||rowidtochar(v_rowid_first));
  dbms_output.put_line('rowid last: '||rowidtochar(v_rowid_second));
  dbms_output.put_line('-------------------------------------------------------');
  dbms_output.put_line('select count(*) from '||p_owner||'.'||p_object_name);
  dbms_output.put_line(' where rowid between chartorowid('''||rowidtochar(v_rowid_first)||''') ');
  dbms_output.put_line('                 and chartorowid('''||rowidtochar(v_rowid_second)||''');');
  dbms_output.put_line('-------------------------------------------------------');
exception
  when others
  then dbms_output.put_line(sqlerrm);  
end;
8 май 08, 18:46    [5643849]     Ответить | Цитировать Сообщить модератору
 Re: "Секционирование" без секционирования  [new]
mbadmin
Member

Откуда:
Сообщений: 11
Nefiga tvoi skript nerabotajet tolko chto poproboval
------------------------------------------------------
owner : XXXX
table name : XXXXX
tablespace_name : USERS
block_size : 16384
extend_id : 0
rowid first : AAAVSGAADAAAMqtAAA
rowid last : AAAVSGAADAAAMqwEAA
-------------------------------------------------------
select count(*) from MBADMIN.TMP_DBA_INDEXES
where rowid between chartorowid('AAAVSGAADAAAMqtAAA')
and chartorowid('AAAVSGAADAAAMqwEAA');
-------------------------------------------------------

select vosvrachajet 0 hota u mena v tablize 42434 sapisi!!!!
9 май 08, 10:37    [5644660]     Ответить | Цитировать Сообщить модератору
 Re: "Секционирование" без секционирования  [new]
mayton
Member

Откуда: loopback
Сообщений: 49819
...далее делать выборку по диапазону rowid


Абсурд какой-то. А почему-бы сразу не проводить выборку по диапазону блоков, экстентов и датафайлов?
9 май 08, 13:20    [5644850]     Ответить | Цитировать Сообщить модератору
 Re: "Секционирование" без секционирования  [new]
RA\/EN
Member

Откуда:
Сообщений: 3659
SQL> select count(*) from tabr where rowid between 'AAARzGAAEAAAEnGADA' and 'AAARzGAAEAAAEnGADw';

  COUNT(*)
----------
        49


Execution Plan
----------------------------------------------------------
Plan hash value: 3473064075

-------------------------------------------------------------------------------------
| Id  | Operation                    | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |      |     1 |    12 |    47   (3)| 00:00:01 |
|   1 |  SORT AGGREGATE              |      |     1 |    12 |            |          |
|*  2 |   TABLE ACCESS BY ROWID RANGE| TABR |   128 |  1536 |    47   (3)| 00:00:01 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access(ROWID>='AAARzGAAEAAAEnGADA' AND ROWID<='AAARzGAAEAAAEnGADw')

Note
-----
   - dynamic sampling used for this statement


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          5  consistent gets
          0  physical reads
          0  redo size
        418  bytes sent via SQL*Net to client
        415  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL>
Все нормально работает, а у тех, у кого не получается, может, просто в экстенте под номером "0" строк нет...
9 май 08, 15:18    [5645038]     Ответить | Цитировать Сообщить модератору
 Re: "Секционирование" без секционирования  [new]
Деев И.
Member

Откуда: отсюда
Сообщений: 783
mayton
...далее делать выборку по диапазону rowid


Абсурд какой-то. А почему-бы сразу не проводить выборку по диапазону блоков, экстентов и датафайлов?


Забыл третий параметр в скрипте прокомментировать - номер экстента.

Это не для обычных приложений, разумеется. Может пригодиться при миграции данных. Например, чтобы снизить объем используемого в одной транзакции UNDO при обновлении больших объемов данных в хранилищах.

Или, например, сильно раздулся лог материализованного представления - его можно тоже по частям обработать.

Или секционируем мы здоровую таблицу - а дополнительного места нет ни на файловой системе ни на дисках. Как быть?
Если 10-ка - можно начать перенос данных с верхних экстентов. Верхние экстенты исходной таблицы освобождаем, перекачивая данные, далее снижаем HWM с помощью SHRINK (хотя это может быть и медленно. Может, еще какой-то хакерский способ есть? DEALLOCATE UNUSED ведь не пройдет уже. Может быть, есть способ отметить экстент как свободный на уровне словаря) Таким образом, не нужно двойного объема пространства для секционирования и не нужно делать экспорт, удалять исходную таблицу, чтобы потом залить данные в уже секционированную.
9 май 08, 18:55    [5645430]     Ответить | Цитировать Сообщить модератору
 Re: "Секционирование" без секционирования  [new]
Владимир Бегун
Member

Откуда: Redwood Shores, CA USA
Сообщений: 1707
Деев И.
....
ad_parallel, идея старая и широкоиспользуемая, но по видимому в узких кругах ;)
9 май 08, 19:39    [5645518]     Ответить | Цитировать Сообщить модератору
 Re: "Секционирование" без секционирования  [new]
wurdu
Member

Откуда: Владивосток
Сообщений: 4441
Маленькое замечание
вместо
select o.object_id into v_object_id from dba_objects o
должно быть
select o.data_object_id into v_object_id from dba_objects o
10 май 08, 10:29    [5646075]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить