среда, 31 марта 2010 г.

Перенос LOBSEGMENT и LOBINDEX в другой Tablespace.

Данный скрипт генерирует код, который нужно выполнить для переноса LOBSEGMENT и LOBINDEX в другой Tablespace.

DECLARE
V_OLD_TABLESPACE VARCHAR2(100):='USERS';
V_NEW_TABLESPACE VARCHAR2(100):='TEMP';
BEGIN
FOR XX IN (
SELECT L.TABLE_NAME, L.COLUMN_NAME, L.INDEX_NAME
FROM USER_LOBS L, USER_SEGMENTS S
WHERE (S.SEGMENT_NAME=L.SEGMENT_NAME) AND (S.TABLESPACE_NAME=V_OLD_TABLESPACE)) LOOP
DBMS_OUTPUT.PUT_LINE('ALTER TABLE '||XX.TABLE_NAME||' MOVE LOB('||XX.COLUMN_NAME||')
STORE AS (TABLESPACE '
||V_NEW_TABLESPACE||' INDEX '||XX.INDEX_NAME||'(TABLESPACE '||
V_NEW_TABLESPACE||' STORAGE (MAXEXTENTS UNLIMITED)));');
END LOOP;
END;

Пример результата работы данного скрипта:

ALTER TABLE QUERY_TBL MOVE LOB(QUERY_TEXT) STORE AS
(TABLESPACE TEST INDEX SYS_IL0000049532C00011$(TABLESPACE TEST
STORAGE (MAXEXTENTS UNLIMITED)));
ALTER TABLE QUERY_PARM_TBL MOVE LOB(QUERY_PARMS) STORE AS
(TABLESPACE TEST INDEX SYS_IL0000049553C00003$(TABLESPACE TEST
STORAGE (MAXEXTENTS UNLIMITED)));
ALTER TABLE OFS_ITEMS MOVE LOB(DATA) STORE AS (TABLESPACE TEST
INDEX SYS_IL0000177335C00011$(TABLESPACE TEST
STORAGE (MAXEXTENTS UNLIMITED)));
После этого сделать rebuild индексов (в данном случае, в таблицах QUERY_TBL, QUERY_PARM_TBL,
OFS_ITEMS).

Найдено на просторах www.sql.ru

вторник, 30 марта 2010 г.

Уменьшение размера tablespace в Oracle.

После чистки таблиц в базе, а затем выполнения их дефрагментации, высвободилось достаточно много свободного места в табличном пространстве. В итоге 24 datafile's размером по 32Гб каждый получились заняты процентов по 20-25%. Решено было уменьшить размеры самих datafile's, чтобы освободить место на файловой системе.

Размеры tablespace's можно посмотреть так:

select a.tablespace_name ,
round(a.bytes_alloc / 1024 / 1024, 2) m_alloc,
round(nvl(b.bytes_free, 0) / 1024 / 1024, 2) m_free,
round((a.bytes_alloc - nvl(b.bytes_free, 0)) / 1024 / 1024, 2) m_used,
round(maxbytes/1048576,2) Max
from ( select f.tablespace_name,
sum(f.bytes) bytes_alloc,
sum(decode(f.autoextensible, 'YES',f.maxbytes,'NO', f.bytes)) maxbytes
from dba_data_files f
group by tablespace_name) a,
( select f.tablespace_name,
sum(f.bytes) bytes_free
from dba_free_space f
group by tablespace_name) b
where a.tablespace_name = b.tablespace_name (+);


Результат выглядит примерно так:





Здесь видно, что USERS занимает 618Gb, а использует 129Gb. Посмотрим до какого размера можно сжать tablespace.

select dba_data_files.file_name,
dba_data_files.file_id,
dba_data_files.tablespace_name,
ceil((nvl(hwm, 1) * db_block_size) / 1024 / 1024) smallest,
ceil(blocks * db_block_size / 1024 / 1024) currsize,
ceil(blocks * db_block_size / 1024 / 1024) -
ceil((nvl(hwm, 1) * db_block_size) / 1024 / 1024) savings
from dba_data_files,
(select file_id,
max(block_id + blocks - 1) hwm
from dba_extents
group by file_id) b,
(select value db_block_size from v$parameter where name = 'db_block_size') c
where dba_data_files.file_id = b.file_id(+);


Результат:





Там, где есть возможность уменьшить размер datafale's - уменьшаем. Т.е. datafile
E:\ORACLE\DATA\DSAUDIT\USERS19.DBF можно уменьшить до 6200Мб.

Пример:

SQL>alter database datafile 'E:\ORACLE\DATA\DSAUDIT\USERS19.DBF' resize 6200M;

Остальные datafile's уменьшить не получается, т.к. в них данные раскиданы по всему пространству. А это значит, что таблички нужно переносить в другой tablespace. Можно перенести все сразу таблички, уменьшить размер, и вернуть таблички на место. А можно найти объекты, которые раскиданы по tablespace, и переместить только их.
select dba_extents.owner,
dba_extents.segment_name,
dba_extents.segment_type,
dba_extents.tablespace_name,
dba_extents.file_id,
dba_extents.block_id
from dba_extents,
(select file_id,
max(block_id) max_block_id
from dba_extents
group by file_id) b
where dba_extents.file_id = b.file_id and
dba_extents.block_id = b.max_block_id;

Результат:





Для переноса таблицы в другой tablespace:

SQL>alter table PINECONE.QUERY_TABLE_TBL move tablespace TEST;

Затем в перенесённой таблице необходимо сделать rebuild индексов.
Посмотрим какие индексы есть в таблице

SQL>SELECT STATUS, INDEX_NAME FROM USER_INDEXES WHERE TABLE_NAME = 'QUERY_TABLE_TBL';

STATUS INDEX_NAME
-------- ------------------------------
UNUSABLE QTT_OWNER_NAME

И делаем непосредственно ребилд

SQL> ALTER INDEX SYS_C005185 REBUILD;

Проверяем

SQL>SELECT STATUS, INDEX_NAME FROM USER_INDEXES WHERE TABLE_NAME = 'QUERY_TABLE_TBL';

STATUS INDEX_NAME
-------- ------------------------------
VALID QTT_OWNER_NAME

Для переноса индексов в другой tablespace:

SQL>alter index PINECONE.SYS_C005180 rebuild tablespace TEST;

Также определяем и переносим другие таблички или индексы,и пробуем снова уменьшить tablespace.

Определяем объекты, находящиеся в корзине:

select decode(partition_name, null,
segment_name,
segment_name || ':' || partition_name) objectname,
segment_type object_type,
owner,
tablespace_name,
header_block
from dba_segments
where tablespace_name = 'PINECONE' and
segment_name like 'BIN$%';
И удаляем их, например так:

SQL>purge table PINECONE."BIN$0IlaH5/6SyGv+h8B8BzJzQ==$0";

Уменьшаем tablespace.

SQL>alter database datafile 'F:\ORACLE\DATA\DSAUDIT\USERS23.DBF' resize 10M;
...
...
...
В итоге получилось так:
Теперь переносим таблицы и индексы обратно.

Составлено на основе материалов http://all-oracle.ru, http://ora-20000.blogspot.com/2009/04/tablespace.html 

понедельник, 22 марта 2010 г.

Как обрезать errorlog не останавливая сервер Sybase ASE.

Способы выполнения этой задачи зависят от версии ASE и платформы, на которой он работает.

Unix-подобные системы.
Здесь стандартный способ обрезать открытый другим процессом - это скопировать в него файл /dev/null. Т.е. :

cat /dev/null > /opt/sybase/YOUSERVERLOG.log

В вашей системе путь к файлу лога может быть другим.
Для выполнения этой команды из ASE можно воспользоваться системной процедурой xp_cmdshell.
Надо также заметить что в силу особенностей работы файловой подсистемы этих ОС, удаление файла лога или переименование пустого файла в файл лога не поможет - ASE будет все так же писать в свой старый файл.

Win32 (все Windows-ы)
Лог может быть обрезан открытием файла лога в редакторе Notepad, удалением всех строк и сохранением его. На самом деле конечно это может быть любой редактор, который не открывает файл в монопольном режиме для чтения и записи.
Кроме того, нужно отметить, что все особенности файловой системы Unix-подобных систем присущи и файловой системе NTFS, так что трюк с cat /dev/null > yourlog
также работает. Утилиту cat можно взять например в пакете CygWin.

Начиная с ASE 12.5 лог можно привязать к прокси-таблице ( в 12.5 появилась возможность делать прокси-таблицы на файлы ОС ) и тогда лог очищается коммандой

SQL>truncate table MYERRORLOG

где MYERRORLOG - прокси-таблица, привязанная к файлу лога ASE.
Этот способ работает на всех платформах, где работает ASE.

Создание копии MBR.

Создание копии MBR

dd if=/dev/sda of=mbr.img bs=446 count=1

Создание копии MBR+таблица разделов

dd if=/dev/sda of=mbr.img bs=512 count=1

Для восстановления параметры if и of поменять местами.

пятница, 19 марта 2010 г.

Пропадает место на разделе (Linux&unix).

Если команда df -h показывает заполненный раздел (например /var), а du -s /var выдаёт гораздо меньший размер, значит какие-то процессы "держат" удалённые файлы.

Получить список удалённых файлов и "держащих" их процессов можно командой
lsof | grep deleted

К сожалению lsof далеко не всегда показывает правильно статус (deleted), в таком случае можно проверить на существование все выданные им пути к файлам. Топорный способ:
lsof | grep REG| awk '{print $9}' | xargs ls -l >/dev/null

lsof в первую очередь вам выдал процессы, которые эти файлы держат, а также размеры файлов. Дальше виновнику посылка сигнала HUP или действие стартового скрипта reload. Ну а если не поможет, то stop/start. Перезагружать всю машину нет никакого смысла.

Фрагментация таблиц в Oracle.

1. Для начала посмотрим размер таблицы(с фрагментацией)

SQL> SELECT TABLE_NAME, ROUND((BLOCKS*8),2)||'KB' "SIZE"
FROM USER_TABLES
WHERE TABLE_NAME = 'SESSION_TBL';

TABLE_NAME SIZE
------------------------------ ------------------------------------------
SESSION_TBL 7497760KB

2. Определим реальный размер данных

SQL> SELECT TABLE_NAME, ROUND((NUM_ROWS*AVG_ROW_LEN/1024),2)||'KB' "SIZE"
FROM USER_TABLES
WHERE TABLE_NAME = 'SESSION_TBL';

TABLE_NAME SIZE
------------------------------ ------------------------------------------
SESSION_TBL 4032361,52KB


В итоге 7497760KB - 4032361KB = 3465399 KB используется без толку.
В процентном соотношении 46% занятого пространства не используется.

3. Для удаления фрагментации потребуется реорганизовать таблицу.
Есть несколько опций для реорганизации фрагментированных таблиц.
Рассмотрим один вариант - перенос таблицы и пересоздание индексов.

4. Посмотрим какие индексы имеются в данной таблице

SQL> SELECT STATUS, INDEX_NAME FROM USER_INDEXES
WHERE TABLE_NAME = 'SESSION_TBL';

STATUS INDEX_NAME
-------- ------------------------------
VALID SYS_C005180
VALID ST_LCL_SES_STRT_TS

5. Начинаем. Необходимо, чтобы в tablespaces имелось свободное место.

SQL> ALTER TABLE SESSION_TBL MOVE;

Table altered.

6. Проверим индексы.

SQL> SELECT STATUS, INDEX_NAME FROM USER_INDEXES
WHERE TABLE_NAME = 'SESSION_TBL';

STATUS INDEX_NAME
-------- ------------------------------
UNUSABLE SYS_C005180
UNUSABLE ST_LCL_SES_STRT_TS

7. Пересоздаём индексы.

SQL> ALTER INDEX SYS_C005180 REBUILD;

Index altered.

SQL> ALTER INDEX ST_LCL_SES_STRT_TS REBUILD;

Index altered.

8. Проверяем.

SQL> SELECT STATUS, INDEX_NAME FROM USER_INDEXES
WHERE TABLE_NAME = 'SESSION_TBL';

STATUS INDEX_NAME
-------- ------------------------------
VALID SYS_C005180
VALID ST_LCL_SES_STRT_TS

8. Собираем статистику.

SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS('workusers','SESSION_TBL');

PL/SQL procedure successfully completed.

9. Проверяем размеры данных в даблице и размер самой таблицы.

SQL> SELECT TABLE_NAME, ROUND((BLOCKS*8),2)||'KB' "SIZE"
FROM USER_TABLES
WHERE TABLE_NAME = 'SESSION_TBL';

TABLE_NAME SIZE
------------------------------ ------------------------------------------
SESSION_TBL 4780632KB

SQL> SELECT TABLE_NAME, ROUND((NUM_ROWS*AVG_ROW_LEN/1024),2)||'KB' "SIZE"
FROM USER_TABLES
WHERE TABLE_NAME = 'SESSION_TBL';

TABLE_NAME SIZE
------------------------------ ------------------------------------------
SESSION_TBL 4032361,52KB

В итоге 4780632KB - 4032361KB = 748271KB


Т.е. освободилось 36% от ранее занятого таблицей пространства.

Составлено на основе материалов http://all-oracle.ru