Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Oracle > Как сравнить данные в таблицах?


Автор: Tigress 20.7.2007, 09:51
Есть три сервера. В реплике. Реплика умирает (по 1000 битых транзакций на каждой ветке) smile ,  потому как должность админа вакантна  Буду останавливать базу и пытаться что-то сделать с этим. 

Нужен такой код, который будет сравнивать данные в таблицах на главном сервере с данными в таблицах двух других серверов. И если вдруг на главном сервере в таблице нет какой-то строки, которая есть в таблице на другом сервере (а таких случаев будет дофига), то добавлять ее (строку) в таблицу на главном серваке.

Помогите, пожалуйста с составлением кода. Идеи такие: 
Код

select a, b 
from T 
minus 
select a, b
from T@адрес_другого_сервера

Таблиц то дофига и больше...как бы это все оптимизировать (Ну и чтоб не три дня сравнивало, а хотяб за пару часов справилось)
Всем заранее большее СПАСИБО!

Автор: LSD 20.7.2007, 10:25
Есть сильное подозрение, что подобный селект на больших таблицах, приведет к "смерти" сервера. Я бы делал через курсоры, делаем два селекта, с сортировкой по первичному ключу и вперед.

Автор: Tigress 20.7.2007, 10:40
LSD, в том то и дело, что боюсь, что всё умрет окончательно. Поэтому и спрашиваю совета. 
У меня таблиц (select count(*) from user_objects where user_objects.object_type='TABLE')  537 штук

То есть, кроме того, что нужно позаботится о быстроте сравнения пары таблиц, нужно еще и сделать так, чтобы автоматом перебирались все таблицы. Не в ручную же для каждой код вводить в самом деле. 

И это все дело должно отработать 2 раза! (сравнивать же с двумя базами)

>Я бы делал через курсоры, делаем два селекта, с сортировкой по первичному ключу и вперед.

А после курсора что? Построчно сравнивать? Ведь не совпадающие строки не обязательно в конце таблицы стоять будут (и не будут они там стоять сразу говорю)...
Можешь код набросать? а то чё то ИЯ БЛОНДИНКО  smile 







Автор: Sqlninja 20.7.2007, 11:21
а че - репликация идет в режиме non-stop?
я бы сделал на удаленных серваках snapshot нужных таблиц, включил бы их в master refresh group. а на главном серваке обновляемые таблицы надо привязать к ней, и регулярно рефрешить.
Код

...
BEGIN
   DBMS_REFRESH.REFRESH ('&&_SCHEMA..&&_REP_GROUP.');
END;
/


короче стандартная репликация, только урезанная.

Автор: Tigress 20.7.2007, 11:36
Sqlninja, наверно ж нон стоп.
Вернее, там уже пару месяцев ВСЕ ПЛОХО!!! Из за количества битых транзакций - база практически стоит...
Задача начальством поставлена такая..
1. Остановить базу, у нас собрать в талицы все данные, которых нет, но они есть в таблицах на других серваках. 
2. Похерить все данные таблиц на тех серваках
3. И залить их туда заново...

Я не админ нифига...
Я б так:
сделала б курсор по всем таблицам 
cursor cur is 
select object_name as NameTable from user_objects 
where user_objects.object_type='TABLE' 
order by object_name

а потом по каждой строке в курсоре  for rcur in cur loop (не знаю тока можно ли так имя передать):
 
insert into NameTable
  ( select * from rcur.NameTable@NameLink
    minus
    select * from rcur.NameTable 
  )

Но боюсь...это будет неделю длится! Или я ошибаюсь? Помогиииите! Оптимизируйте решение, плз.

Автор: Sqlninja 20.7.2007, 11:51
снимите битые транзакции вручную через Enterprise Manager Console. или пишите на email [email protected].

Автор: LSD 20.7.2007, 12:20
Цитата(Tigress @  20.7.2007,  11:40 Найти цитируемый пост)
А после курсора что? Построчно сравнивать? Ведь не совпадающие строки не обязательно в конце таблицы стоять будут (и не будут они там стоять сразу говорю)...

Бежишь сравниваешь PK обоих курсоров. 
- Если они равны, значит это одна и та же запись, далее сравниваешь поля.
- Если - не равны, значит эту запись надо добавить в ту БД PK которой больше.

Цитата(Tigress @  20.7.2007,  11:40 Найти цитируемый пост)
Можешь код набросать?

Сейчас нет времени, попытайся сам. Если не получится - пиши.

Автор: Tigress 20.7.2007, 12:54
Как то так?
Код

cursor cur1 is 
select * from NameTable;

cursor cur2 is 
select * from NameTable@NameLink;

for rcur1 in cur1 loop
    for rcur2 in cur2 loop
    if rcur1.id=rcur2.id then begin F=True; Goto Metka end;
    end loop;
Metka:
 if F=true then begin insert into NameTable ... end;
 F=false;
end loop;

Так будет быстрее работать, чем при Minus?
И еще такой вопрос, как-то можно задать имя таблицы как переменную. Ну чтоб NameTable каждый раз не вручную править, а хотя бы чтоб это был параметр функции?

Автор: LSD 20.7.2007, 13:56
При использовании minus, у тебя все данные в таблице будут закачиваться в сервер. Если сервер это потянет, то работать будет даже быстрее. Но вот только я как-то сомневаюсь, что сервак способен это потянуть.

Автор: Sherst 20.7.2007, 13:56
Кайт говорил что если возможно использовать sql запросы то лучше использовать их.

Автор: Tigress 20.7.2007, 14:23
LSD, спасибо. Буду курсором. Примерно как написала. Потому как параллельно по ним бежать не удастся - ключи нельзя сравнить однозначно на больше-меньше (так чтоб точно знать в какую таблицу копировать).

А что скажете по поводу задания имени таблицы как параметра???


Sherst, да, Томас возможно так говорил...какие выводы?  smile  smile  smile 

Автор: DimW 23.7.2007, 08:04
Цитата(Sherst @  20.7.2007,  13:56 Найти цитируемый пост)
Кайт говорил что если возможно использовать sql запросы то лучше использовать их. 


вот именно по этому делайте так:

Код

drop table table1
/
CREATE TABLE table1 AS SELECT * FROM table1@сервер1;
/


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


Цитата(Tigress @  20.7.2007,  14:23 Найти цитируемый пост)
А что скажете по поводу задания имени таблицы как параметра???


поиск по - execute immediate

Автор: Tigress 23.7.2007, 09:42
Попробую сделать так...
CREATE OR REPLACE PROCEDURE Update_Tables(NameLink in varchar2)
is
NameTable varchar(50);
NameTable_with_Link varchar(100);
Rec_Count_in_Table integer;
Rec_Count_in_Table_with_Link integer;
cursor CUR is
select table_name 
from user_tables;

BEGIN
    FOR r IN CUR LOOP
      
      NameTable=r.table_name;
      NameTable_with_Link=NameTable+'@'+NameLink;
      
      execute immediate 'select count(*) into Rec_Count_in_Table from' || NameTable; 
      execute immediate 'select count(*) into Rec_Count_in_Table_with_Link from' || NameTable_with_Link; 
      if Rec_Count_in_Table_with_Link<>Rec_Count_in_Table then
      execute immediate 
      'insert into'|| NameTable || '( select * from ' || NameTable_with_Link ||' minus select * from ' || NameTable ||' )';
      end if;
    End Loop;  
     
    
END;

нормально?

Автор: DimW 23.7.2007, 12:55
Цитата(Tigress @  23.7.2007,  09:42 Найти цитируемый пост)
нормально? 


нет.


Цитата(Tigress @  23.7.2007,  09:42 Найти цитируемый пост)
execute immediate 'select count(*) into Rec_Count_in_Table from' || NameTable; 
      execute immediate 'select count(*) into Rec_Count_in_Table_with_Link from' || NameTable_with_Link; 
      if Rec_Count_in_Table_with_Link<>Rec_Count_in_Table then

на мой взгляд безполезные действия. да еще и не правельно написаны.

Автор: Tigress 23.7.2007, 13:15
Точно бесполезные...
Почему неправильно?

Автор: DimW 23.7.2007, 13:24
Цитата(Tigress @  23.7.2007,  13:15 Найти цитируемый пост)
Почему неправильно?


потому что так:
Код

execute immediate 'select count(*) into Rec_Count_in_Table from' || NameTable;


в переменную Rec_Count_in_Table ни чего не запишешь.
а вот так да:
Код

execute immediate 'select count(*) into :Rec_Count_in_Table from' || NameTable using in out  Rec_Count_in_Table;
 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)