Начало Database 10g Прехвърляне на база от CL8MSWIN1251 в AL32UTF8
Прехвърляне на база от CL8MSWIN1251 в AL32UTF8
Четвъртък, 11 Март 2010 09:21
Всеки, който се е опитал да прехвърли данни от база с 8 битов CHARACTERSET (WE8ISO8859P1, WE8MSWIN1251 и т.н.) към база с 16 битов (AL32UTF8) неминуемо се е сблъсквал с проблема свързан с размерността на колоните от тип CHAR и VARCHAR2.

Проблемът

Основната грижа идва от факта, че когато колоната се дефинира например като VARCHAR2(20), за базата данни това означава VARCHAR2 с дължина 20 байта. И докато при CL8MSWIN1251 един знак кирилица се представя точно с един байт, то при AL32UTF8 нещата не стоят така. На теория UTF8 може да използва до 6 байта за представянето на знак, което означава, че за 20 знака може да са му нужни до 120 байта.

Да видим какво би се получило при опит за реално прехвърляне на данни между две такива бази (наречени DEVDB и ORCL) на една тестова схема (наречена DELO). Започваме с базата – източник на данни. Нека първо погледнем нейния CHARACTERSET:

C:\Documents and Settings\Administrator>sqlplus system@devdb

Export: Release 10.2.0.1.0 - Production on ╤Ё фр, 03 ╘хтЁєрЁш, 2010 9:14:42

Copyright (c) 1982, 2005, Oracle. All rights reserved.

Enter password:

Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options

SQL> select value from v$nls_parameters where parameter='NLS_CHARACTERSET';

VALUE
----------------------------------------------------------------
CL8MSWIN1251

SQL>

Създаваме дъмп на схема от въпросната база, която съдържа известно количество данни на кирилица:

C:\Documents and Settings\Administrator>expdp system@devdb directory=data_pump_dir dumpfile=delo.dmp schemas=delo

Export: Release 10.2.0.1.0 - Production on ╤Ё фр, 03 ╘хтЁєрЁш, 2010 9:16:44

Copyright (c) 2003, 2005, Oracle. All rights reserved.
Password:

Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
Starting "SYSTEM"."SYS_EXPORT_SCHEMA_01": system/********@devdb directory=data_pump_dir dumpfile=delo.dmp schemas=delo
Estimate in progress using BLOCKS method...
Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
Total estimation using BLOCKS method: 233.6 MB
Processing object type SCHEMA_EXPORT/USER
Processing object type SCHEMA_EXPORT/SYSTEM_GRANT
Processing object type SCHEMA_EXPORT/ROLE_GRANT
Processing object type SCHEMA_EXPORT/DEFAULT_ROLE
Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
Processing object type SCHEMA_EXPORT/TABLE/TABLE
Processing object type SCHEMA_EXPORT/TABLE/GRANT/OWNER_GRANT/OBJECT_GRANT
Processing object type SCHEMA_EXPORT/TABLE/INDEX/INDEX
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Processing object type SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type SCHEMA_EXPORT/PROCEDURE/PROCEDURE
Processing object type SCHEMA_EXPORT/PROCEDURE/ALTER_PROCEDURE
Processing object type SCHEMA_EXPORT/VIEW/VIEW
Processing object type SCHEMA_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
. . exported "DELO"."TABLE_REZOL_DOC" 79.48 MB 127843 rows
. . exported "DELO"."TABLE_FIRST" 19.78 MB 127302 rows
. . exported "DELO"."DOC" 14.05 MB 76821 rows
. . exported "DELO"."JOURNAL" 11.74 MB 104861 rows
. . exported "DELO"."REZOL" 8.185 MB 47088 rows
. . exported "DELO"."DELO" 6.825 MB 46306 rows
. . exported "DELO"."DIC_ANOT" 7.045 MB 575042 rows
...
. . exported "DELO"."T_SLUJBI128" 0 KB 0 rows
. . exported "DELO"."USLUGI" 0 KB 0 rows
. . exported "DELO"."VERSION1" 0 KB 0 rows
Master table "SYSTEM"."SYS_EXPORT_SCHEMA_01" successfully loaded/unloaded
******************************************************************************
Dump file set for SYSTEM.SYS_EXPORT_SCHEMA_01 is:
C:\ADMIN\DEVDB\DPDUMP\DELO.DMP
Job "SYSTEM"."SYS_EXPORT_SCHEMA_01" successfully completed at 09:18:26

C:\Documents and Settings\Administrator>

Така получения дъмп прехвърляме на друг сървър и се опитваме да заредим в работещата там база. Да видим преди това нейния CHARACTERSET:

[oracle@db1 ~]$ sqlplus system@orcl

SQL*Plus: Release 11.2.0.1.0 Production on Wed Feb 3 08:59:38 2010

Copyright (c) 1982, 2009, Oracle. All rights reserved.

Enter password:

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
Data Mining and Real Application Testing options

SQL> select value from v$nls_parameters where parameter='NLS_CHARACTERSET';

VALUE
----------------------------------------------------------------
AL32UTF8

SQL>

Опитваме да заредим данните по следния начин:

[oracle@db1 /]$ impdp system@orcl directory=ORABACKUP dumpfile=DELO.DMP remap_tablespace=DELO:USERS

Import: Release 11.2.0.1.0 - Production on Wed Feb 3 09:04:13 2010

Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
Password:

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
Data Mining and Real Application Testing options
Master table "SYSTEM"."SYS_IMPORT_FULL_01" successfully loaded/unloaded
Starting "SYSTEM"."SYS_IMPORT_FULL_01": system/********@orcl directory=ORABACKUP dumpfile=DELO.DMP remap_tablespace=DELO:USERS
Processing object type SCHEMA_EXPORT/USER
Processing object type SCHEMA_EXPORT/SYSTEM_GRANT
Processing object type SCHEMA_EXPORT/ROLE_GRANT
Processing object type SCHEMA_EXPORT/DEFAULT_ROLE
Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
Processing object type SCHEMA_EXPORT/TABLE/TABLE

ORA-02374: conversion error loading table "DELO"."TABLE_REZOL_DOC"
ORA-12899: value too large for column COL_P (actual: 677, maximum: 500)
ORA-02372: data for row: COL_P : 0X'CFD0C5C4D1D2C0C2DFCDC520C220CED2C4C5CB20CAC0CDD6C5'

ORA-02374: conversion error loading table "DELO"."TABLE_REZOL_DOC"
ORA-12899: value too large for column COL_P (actual: 503, maximum: 500)
ORA-02372: data for row: COL_P : 0X'CFCED1D2DACFC8CBCE20CFC8D2C0CDC52020CED220CDCF2020'

ORA-02374: conversion error loading table "DELO"."TABLE_REZOL_DOC"
ORA-12899: value too large for column COL_V (actual: 340, maximum: 300)
ORA-02372: data for row: COL_V : 0X'C3C5CEC3D0C0D4D1CAC820C8CDD1D2C8D2D3D220CDC020C1C0'

ORA-02374: conversion error loading table "DELO"."TABLE_REZOL_DOC"
ORA-12899: value too large for column COL_P (actual: 531, maximum: 500)
ORA-02372: data for row: COL_P : 0X'C8C7CFD0C0D9C0D220CFCE20C5CBC5CAD2D0CECDCDC0D2C020'
...
ORA-02374: conversion error loading table "DELO"."DOC"
ORA-12899: value too large for column ANOT (actual: 300, maximum: 254)
ORA-02372: data for row: ANOT : 0X'CFD0C5C4CBCEC6C5CDC8C520C7C020C2CACBDED7C2C0CDC520'

. . imported "DELO"."DOC" 14.05 MB 70169 out of 76821 rows
. . imported "DELO"."USLUGI" 0 KB 0 rows
. . imported "DELO"."VERSION1" 0 KB 0 rows
...
. . imported "DELO"."SID_DOC" 0 KB 0 rows
. . imported "DELO"."SPR_DOP" 0 KB 0 rows
. . imported "DELO"."SPR_UPR" 0 KB 0 rows
. . imported "DELO"."SRESTU" 0 KB 0 rows
. . imported "DELO"."table_rezol_doc_bez" 0 KB 0 rows
. . imported "DELO"."TABLE_REZOL_DOC_bez" 0 KB 0 rows
. . imported "DELO"."T_DNEVNIK_COPY" 0 KB 0 rows
. . imported "DELO"."T_SLUJBI128" 0 KB 0 rows
. . imported "DELO"."USLUGI" 0 KB 0 rows
. . imported "DELO"."VERSION1" 0 KB 0 rows
Processing object type SCHEMA_EXPORT/TABLE/GRANT/OWNER_GRANT/OBJECT_GRANT
Processing object type SCHEMA_EXPORT/TABLE/INDEX/INDEX
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Processing object type SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type SCHEMA_EXPORT/PROCEDURE/PROCEDURE
Processing object type SCHEMA_EXPORT/PROCEDURE/ALTER_PROCEDURE
Processing object type SCHEMA_EXPORT/VIEW/VIEW
Processing object type SCHEMA_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Job "SYSTEM"."SYS_IMPORT_FULL_01" completed with 1 error(s) at 09:12:52
[oracle@db1 /]$

Виждаме, че за таблицата DOC импортът е изпуснал над 6000 записа (76821-70169=6652). Този проблем ясно се идентифицира чрез ORA-12899 записите в лог файла на импорта. Те имат следния вид:

ORA-02374: conversion error loading table "DELO"."TABLE_REZOL_DOC"
ORA-12899: value too large for column COL_V (actual: 340, maximum: 300)
ORA-02372: data for row: COL_V : 0X'C3C5CEC3D0C0D4D1CAC820C8CDD1D2C8D2D3D220CDC020C1C0'

Тази информация показва, че колоната COL_V е дефинирана като VARCHAR2 с размерност 300 байта, което при CL8MSWIN1251 позволява запис на 300 знака. Конвертираният до AL32UTF8 запис обаче е с дължина 340 байта и няма как да влезе в така дефинираната колона.

Решението

За да решим този проблем може да опитаме да сменим стойността на параметъра на базата NLS_LENGTH_SEMANTICS. Неговата стандартна стойност е BYTE, което кара базата да заделя за VARCHAR2(20) - 20 байта. Ако зададем стойност на този параметър CHAR, тогава за VARCHAR2(20) базата ще заделя място като за 20 знака в съответния encoding. За съжаление обаче, това няма да ни помогне в конкретния случай. Data Pump не се съобразява с този параметър и щом една колона е експортирана с максимален размер от 20 байта, тя пак ще бъде създадена по същия начин, дори стойността на NLS_LENGTH_SEMANTICS да е CHAR.

Нека видим как можем да се справим с този проблем.

Първо, ако вече сме опитали един неуспешен импорт, трябва да премахнем частично влезлите данни. Изтриваме направо целия потребител:

[oracle@db1 /]$ sqlplus sys@orcl as sysdba

SQL*Plus: Release 11.2.0.1.0 Production on Wed Feb 3 09:53:52 2010

Copyright (c) 1982, 2009, Oracle. All rights reserved.

Enter password:

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
Data Mining and Real Application Testing options

SQL> drop user delo cascade;

User dropped.

SQL>

Техниката, която ще използваме за да направим успешен импорт работи по следния начин:

1.Импортираме само обектите от дъмпа, като не зареждаме данните в тях;
2.Редактираме всяка VARCHAR2 и CHAR колона на таблиците и променяме зададената й дължина в байтове, като я заменяме с дължина в знаци;
3.Импортираме данните в таблиците, чиито колони вече имат правилната размерност;

Започваме с първата стъпка, а именно – импортираме само метаданните на схемата като използваме опцията content=metadata_only на impdp:

[oracle@db1 /]$ impdp system@orcl directory=ORABACKUP dumpfile=DELO.DMP remap_tablespace=DELO:USERS content=metadata_only

Import: Release 11.2.0.1.0 - Production on Wed Feb 3 10:14:15 2010

Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
Password:

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
Data Mining and Real Application Testing options
Master table "SYSTEM"."SYS_IMPORT_FULL_01" successfully loaded/unloaded
Starting "SYSTEM"."SYS_IMPORT_FULL_01": system/********@orcl directory=ORABACKUP dumpfile=DELO.DMP remap_tablespace=DELO:USERS content=metadata_only
Processing object type SCHEMA_EXPORT/USER
Processing object type SCHEMA_EXPORT/SYSTEM_GRANT
Processing object type SCHEMA_EXPORT/ROLE_GRANT
Processing object type SCHEMA_EXPORT/DEFAULT_ROLE
Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
Processing object type SCHEMA_EXPORT/TABLE/TABLE
Processing object type SCHEMA_EXPORT/TABLE/GRANT/OWNER_GRANT/OBJECT_GRANT
Processing object type SCHEMA_EXPORT/TABLE/INDEX/INDEX
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Processing object type SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type SCHEMA_EXPORT/PROCEDURE/PROCEDURE
Processing object type SCHEMA_EXPORT/PROCEDURE/ALTER_PROCEDURE
Processing object type SCHEMA_EXPORT/VIEW/VIEW
Processing object type SCHEMA_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Job "SYSTEM"."SYS_IMPORT_FULL_01" successfully completed at 10:14:52

[oracle@db1 /]$

Преди да опитаме да приложим стъпка 2, трябва да имаме предвид, че тя може да не работи коректно с колони, които се ползват като partition key в таблици с partitioning. Това е така, защото промяната на partition key колона може да инвалидира текущите partition-и на таблицата. По тази причина трябва да проверим, дали някой partition ще бъде засегнат от операцията като използваме следната заявка:

select c.owner, c.table_name, c.column_name, c.data_type, c.char_length
from all_tab_columns c, all_tables t
where c.owner = t.owner
and t.owner = 'DELO'
and c.table_name = t.table_name
and c.char_used = 'B'
and t.partitioned='YES'
and c.table_name not in (select table_name from all_external_tables)
and c.data_type in ('VARCHAR2', 'CHAR')
/

Ето и изпълнението й:

[oracle@db1 orabackup]$ sqlplus system@orcl

SQL*Plus: Release 11.2.0.1.0 Production on Wed Mar 10 13:17:08 2010

Copyright (c) 1982, 2009, Oracle. All rights reserved.

Enter password:

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
Data Mining and Real Application Testing options

SQL> select c.owner, c.table_name, c.column_name, c.data_type, c.char_length
2 from all_tab_columns c, all_tables t
3 where c.owner = t.owner
4 and t.owner = 'DELO'
5 and c.table_name = t.table_name
6 and c.char_used = 'B'
7 and t.partitioned='YES'
8 and c.table_name not in (select table_name from all_external_tables)
9 and c.data_type in ('VARCHAR2', 'CHAR')
10 /

no rows selected

SQL>

Следващото, което трябва да проверим е за наличието на функционални индекси върху някоя от колоните, които ще променяме. Ако върху някоя от колоните има дефиниран функционален индекс при промяната й към CHAR семантика, ще възникне грешка "ORA-30556: functional index is defined on the column to be modified". Именно по тази причина, ако има такива колони трябва да премахнем индекса от тях и в последствие да го създадем наново след промяната на типа. Проверката за тези индекси можем да направим със следния SELECT:

select INDEX_NAME , INDEX_TYPE, TABLE_OWNER, TABLE_NAME, STATUS, FUNCIDX_STATUS from ALL_INDEXES
where INDEX_TYPE not in ('NORMAL', 'BITMAP','IOT - TOP')
and TABLE_OWNER = 'DELO'
and TABLE_NAME in
(select unique (table_name) from dba_tab_columns where char_used ='B')
/

Изпълнението му изглежда по следния начин:

SQL> select INDEX_NAME , INDEX_TYPE, TABLE_OWNER, TABLE_NAME, STATUS, FUNCIDX_STATUS from ALL_INDEXES
2 where INDEX_TYPE not in ('NORMAL', 'BITMAP','IOT - TOP')
3 and TABLE_OWNER = 'DELO' and TABLE_NAME in
4 (select unique (table_name) from dba_tab_columns where char_used ='B')
5 /
6
no rows selected

SQL>

Добра идея е да погледнем и дали в метаданните няма други невалидни обекти, за които трябва да се погрижим ръчно. Това проверяваме така:

SQL> select object_name, object_type, status from dba_objects where status ='INVALID' and owner='DELO';

no rows selected

SQL>

След като сме извършили всички нужни проверки създаваме една таблица наречена SEMANTICS$. В нея ще запишем всички колони, чийто тип ще модифицираме. Създаваме таблицата така:

SQL> create table semantics$(s_owner varchar2(40), s_table_name varchar2(40), s_column_name varchar2(40), s_data_type varchar2(40), s_char_length number);

Table created.

SQL>

За да извадим въпросните колони използваме ALL_TABLES, като намираме тези от тях, чиято дължина е зададена в байтове и чийто тип на данните е CHAR или VARCHAR2. Зареждаме въпросните колони в SEMANTICS$ чрез следния INSERT:

insert into semantics$
select C.owner, C.table_name, C.column_name, C.data_type, C.char_length
from all_tab_columns C, all_tables T
where C.owner = T.owner
and T.owner = 'DELO'
and C.table_name = T.table_name
and C.char_used = 'B'
and T.partitioned != 'YES'
and C.table_name not in (select table_name from all_external_tables)
and C.data_type in ('VARCHAR2', 'CHAR')
/

Изпълнението му изглежда така:

SQL> insert into semantics$
2 select C.owner, C.table_name, C.column_name, C.data_type, C.char_length
3 from all_tab_columns C, all_tables T
4 where C.owner = T.owner
5 and T.owner = 'DELO'
6 and C.table_name = T.table_name
7 and C.char_used = 'B'
8 and T.partitioned != 'YES'
9 and C.table_name not in (select table_name from all_external_tables)
10 and C.data_type in ('VARCHAR2', 'CHAR')
11 /


835 rows created.

SQL>

Виждаме, че за нашия случай в SEMANTIC$ се създават 835 записа. За всеки от тях трябва да изпълним ALTER TABLE, сменяйки дължината на съответната колона. Това можем да автоматизираме чрез следния скрипт:

set serveroutput on
set termout on
declare
cursor c1 is select * from semantics$;
v_statement varchar2(255);
v_nc number(10);
v_nt number(10);
begin
execute immediate
'select count(*) from semantics$' into v_nc;
execute immediate
'select count(distinct s_table_name) from semantics$' into v_nt;
dbms_output.put_line
('ALTERing ' || v_nc || ' columns in ' || v_nt || ' tables');
for r1 in c1 loop
v_statement := 'ALTER TABLE "' || r1.s_owner || '"."' || r1.s_table_name;
v_statement := v_statement || '" modify ("' || r1.s_column_name || '" ';
v_statement := v_statement || r1.s_data_type || '(' || r1.s_char_length;
v_statement := v_statement || ' CHAR))';
dbms_output.put_line(v_statement);
execute immediate v_statement;
end loop;
dbms_output.put_line('Done');
end;
/

Резултатът от изпълнението му изглежда така:

ALTER TABLE "DELO"."DOC" modify ("DB_MASKA" VARCHAR2(20 CHAR))
ALTER TABLE "DELO"."DOC" modify ("NOM_ORDER" VARCHAR2(50 CHAR))
ALTER TABLE "DELO"."DOC" modify ("EMAIL" VARCHAR2(100 CHAR))
ALTER TABLE "DELO"."DOC" modify ("CITY_TEKST" VARCHAR2(50 CHAR))
ALTER TABLE "DELO"."DOC" modify ("OBL_TEKST" VARCHAR2(50 CHAR))
ALTER TABLE "DELO"."DOC" modify ("IZGOTV_T" VARCHAR2(200 CHAR))
ALTER TABLE "DELO"."DOC" modify ("IDVA_OT_T" VARCHAR2(200 CHAR))
ALTER TABLE "DELO"."DOC" modify ("IME_FILE" VARCHAR2(100 CHAR))
....
ALTER TABLE "DELO"."APP_VERSION" modify ("VER" VARCHAR2(25 CHAR))
ALTER TABLE "DELO"."APP_VERSION" modify ("FILE_NAME" VARCHAR2(50 CHAR))
ALTER TABLE "DELO"."APP_PC" modify ("VER" VARCHAR2(25 CHAR))
ALTER TABLE "DELO"."APP_PC" modify ("NAME_PC" VARCHAR2(50 CHAR))
Done

PL/SQL procedure successfully completed.

SQL>

След като всички колони са променени, можем да премахнем таблицата SEMANTICS$:

SQL> drop table semantics$;

Table dropped.

SQL>

Следващата стъпка е да заредим и самите данни във вече променените таблици:

[oracle@db1 /]$ impdp system@orcl directory=ORABACKUP dumpfile=DELO.DMP remap_tablespace=DELO:USERS content=data_only

Import: Release 11.2.0.1.0 - Production on Wed Mar 10 16:33:34 2010

Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
Password:

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
Data Mining and Real Application Testing options
Master table "SYSTEM"."SYS_IMPORT_FULL_01" successfully loaded/unloaded
Starting "SYSTEM"."SYS_IMPORT_FULL_01": system/********@orcl directory=ORABACKUP dumpfile=DELO.DMP remap_tablespace=DELO:USERS content=data_only
Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
. . imported "DELO"."TABLE_REZOL_DOC" 79.48 MB 127843 rows
. . imported "DELO"."TABLE_FIRST" 19.78 MB 127302 rows
. . imported "DELO"."DOC" 14.05 MB 76821 rows
. . imported "DELO"."JOURNAL" 11.74 MB 104861 rows
. . imported "DELO"."REZOL" 8.185 MB 47088 rows
. . imported "DELO"."DELO" 6.825 MB 46306 rows
. . imported "DELO"."DIC_ANOT" 7.045 MB 575042 rows
. . imported "DELO"."EKZ" 5.794 MB 95320 rows
. . imported "DELO"."APP_VERSION" 6.396 MB 34 rows
. . imported "DELO"."DVIG" 5.086 MB 102124 rows
...
. . imported "DELO"."USLUGI" 0 KB 0 rows
. . imported "DELO"."VERSION1" 0 KB 0 rows
Job "SYSTEM"."SYS_IMPORT_FULL_01" successfully completed at 16:38:48

Виждаме, че този път всички данни влизат в базата без нито една грешка.

На финала може като незадължителна стъпка да изпълним UTL_RECOMP, за да компилираме невалидните обекти (ако такива са се появили):

SQL> EXECUTE UTL_RECOMP.RECOMP_PARALLEL(4);

PL/SQL procedure successfully completed.

SQL>

С това зареждането на данните в UTF-8 базата приключва успешно.

Финални забележки

Възможно е в някой случаи при същинското наливане на данните да започнат да възникват грешки от нарушени CONSTRAINT-и. В този случай можем да използваме следната техника, за да изключим CONSTRAINT-ите преди наливането и да ги включим в последствие.

Следните команди създават скрипт наречен tmp_disable.sql, чието изпълнение изключва всички CONSTRAINT-и в зададената потребителска схема.

set feedback off
set verify off
set echo off
set termout off
set pages 80
set heading off
set linesize 120
spool tmp_disable.sql
select 'ALTER TABLE '||c.owner||'.'||substr(c.table_name,1,35)||' DISABLE CONSTRAINT '||constraint_name||';' from dba_constraints c, dba_tables u where (c.table_name = u.table_name) and (c.owner='DELO');

Можем да използваме аналогични команди, за да генерираме и скрипт за тяхното включване:

spool tmp_enable.sql
select 'ALTER TABLE '||c.owner||'.'||substr(c.table_name,1,35)||' ENABLE CONSTRAINT '||constraint_name||';' from dba_constraints c, dba_tables u where (c.table_name = u.table_name) and (c.owner='DELO');

Скриптовете tmp_disable.sql и tmp_enable.sql използваме съответно преди и след наливането на пълните данни чрез Data Pump.

Коментари

Име
URL
Код   
Запис
 

КНИГАТА

Oracle Database Security Book
(c) 2004-2008 Николай Манчев. Освен ако изрично не е споменато нещо друго, всички материали публикувани тук се разпространяват под Creative Commons Attribution License. Материали, коментари и изображения, които не са създадени и подписани от мен са собственост на съответните им автори.