-
Есть две БД, под управлением firebird. Необходимо сделать зеркальную копию одной таблицы из одной БД в другую. структура и имена таблиц идентичны в двух БД. Сделал ХП:
SET TERM ^ ;
CREATE PROCEDURE STATI_COPY (
CONNECTION Varchar(300) )
AS
declare variable HEADER Varchar(250);
declare variable PAGENUM Varchar(50);
declare variable NUMBER Varchar(40);
declare variable ID Integer;
declare variable STATUS Char(1);
declare variable IsExists Integer;
begin
/*из таблицы главной бд, копируем в подчиненную*/
FOR
EXECUTE STATEMENT ('select ID,NUMBER,PAGENUM,HEADER,STATUS from stati')
ON EXTERNAL :Connection
WITH AUTONOMOUS TRANSACTION
AS USER 'sysdba' PASSWORD 'masterkey'
INTO :ID,:NUMBER,:PAGENUM,:HEADER,:STATUS
DO
if (not exists(select t.id from stati t where t.id=:ID)) Then
insert into stati (ID,NUMBER,PAGENUM,HEADER,STATUS)
values (:ID,:NUMBER,:PAGENUM,:HEADER,:STATUS);
end^
SET TERM ; ^
Собственно все работает, но так как с подчиненной базой тоже идет работа, то в таблице накапливаются "лишние" записи. Для их удаления в этой же процедуре я добавил код:
/*из таблицы в подчиненной бд удаляем лишнии записи*/
FOR
select t.id from stati t into :ID
DO
begin
Execute statement ('select count(r.id) from stati r where r.id=?')(:ID)
ON EXTERNAL :Connection
WITH AUTONOMOUS TRANSACTION
AS USER 'sysdba' PASSWORD 'masterkey'
INTO :IsExists;
if (:IsExists=0) Then
begin
delete from stati where id=:ID;
end
end
И процедура копирования просто зависает, или просто очень долго работает, т.к. обычно выполнение занимало максимум минут 15-20. после дополнения в виде удаления ненужных записей, я прождал сутки, но процедура так и не завершилась. Окончательный вариант выглядит так
SET TERM ^ ;
CREATE PROCEDURE STATI_COPY (
CONNECTION Varchar(300) )
AS
declare variable HEADER Varchar(250);
declare variable PAGENUM Varchar(50);
declare variable NUMBER Varchar(40);
declare variable ID Integer;
declare variable STATUS Char(1);
declare variable IsExists Integer;
begin
/*из таблицы главной бд, копируем в подчиненную*/
FOR
EXECUTE STATEMENT ('select ID,NUMBER,PAGENUM,HEADER,STATUS from stati')
ON EXTERNAL :Connection
WITH AUTONOMOUS TRANSACTION
AS USER 'sysdba' PASSWORD 'masterkey'
INTO :ID,:NUMBER,:PAGENUM,:HEADER,:STATUS
DO
if (not exists(select t.id from stati t where t.id=:ID)) Then
insert into stati (ID,NUMBER,PAGENUM,HEADER,STATUS)
values (:ID,:NUMBER,:PAGENUM,:HEADER,:STATUS);
/*из таблицы в подчиненной бд удаляем лишнии записи*/
FOR
select t.id from stati t into :ID
DO
begin
Execute statement ('select count(r.id) from stati r where r.id=?')(:ID)
ON EXTERNAL :Connection
WITH AUTONOMOUS TRANSACTION
AS USER 'sysdba' PASSWORD 'masterkey'
INTO :IsExists;
if (:IsExists=0) Then
begin
delete from stati where id=:ID;
end
end
end^
SET TERM ; ^
Подскажите, в чем причина такого зависания?
-
Забыл добавить, что процедура в подчиненной БД. т.е. Все execute statement идут к главной БД
-
1. Записать данные из главной БД во временную таблицу в подчиненной БД; 2. Сравнить данные из временной таблицы с имеющимися данными, выполнив при необходимости insert/delete; 3. Очистить временную таблицу.
-
> 1. Записать данные из главной БД во временную таблицу в > подчиненной БД; 2. Сравнить данные из временной таблицы с имеющимися данными, выполнив при необходимости insert/delete;
Зачем? если я и так делаю выборку из главной БД и сравниваю записи, есть такая в подчиненной или нет. если нет, то insert. Следующий цикл проверяет записи из подчиненной с главной, если такой нет в главной, то delete. Зависает на втором цикле, проверки записей в подчиненной на наличие в главной.
И еще, записей в главной БД более 9млн., каждый день прибавляется по 10-30тыс. , т.е. копировать всю таблицу во временную, это ооочень долгий процесс получается.
-
зачем все копировать? достаточно только новые
-
>ford © (11.10.15 12:50) [3] >Зачем? затем, что так гораздо правильнее и существенно быстрее
>т.е. копировать всю таблицу во временную, это ооочень долгий процесс >получается. приведенный Вами код ДВАЖДЫ выполняет операции, необходимые для копирования (за исключением insert во временную)
>И еще, записей в главной БД более 9млн., каждый день прибавляется >по 10-30тыс. собственно, на это ответили в "ухты © (11.10.15 13:26) [4] "
-
Что то я Вас не совсем понял. В моей ХП первый цикл, открывает таблицу в главной БД, берёт каждую запись, и проверяет наличие записи с таким же ID в подчиненной, если таковой нет, то делает insert. Второй цикл, открывает таблицу в подчиненной и проверяет каждую запись на наличие этого ID в главной, если такового нет, то делает delete этой записи.
Копировать 9млн записей во временную таблицу, это не быстрее, поверьте! первичное копирование из главной в подчиненную (т.е. первый цикл ХП), заняло более 15 часов!!!
> ухты © (11.10.15 13:26) [4] > > зачем все копировать? достаточно только новые
Так я и не копирую ВСЕ, я проверяю для каждой наличие в подчиненной, и копирую только те которых нет!!
... DO if (not exists(select t.id from stati t where t.id=:ID)) Then insert into stati (ID,NUMBER,PAGENUM,HEADER,STATUS) values (:ID,:NUMBER,:PAGENUM,:HEADER,:STATUS);
if (not exists вам ни очем не говорит?
> Кщд © (12.10.15 08:13) [5] приведенный Вами код ДВАЖДЫ выполняет операции, необходимые для копирования (за исключением insert во временную)
ГДЕ!? Где Вы увидели временную таблицу? и где ДВАЖДЫ выполнение операций? первый цикл, проверяет наличие новых записей. второй, удаляет не нужные.
Приведите код "правильного" зеркалирования таблиц, в двух разных БД!
-
Вам про Фому а вы про Ерему. Разговор о том что не надо каждый раз перепахивать то что уже перепахано. Вы каждый раз ходите по всей таблице, а зачем? если вам надо только то что изменилось с предыдущего раза? Те что уже скопировали, вы повторно копировать не будете, так и проверять их не зачем.
Вам средства репликации точно не подходят?
-
>ГДЕ!? Где Вы увидели временную таблицу? у Вас - нигде я про это и не писал.
>и где ДВАЖДЫ выполнение операций?
1. >EXECUTE STATEMENT ('select ID,NUMBER,PAGENUM,HEADER,STATUS from stati') это полный проход по таблице в главной БД т.е. Вы УЖЕ выбрали все данные из главной
2. >Execute statement ('select count(r.id) from stati r where r.id=?')(:ID) это ещё один проход по таблице из главной
1 + 1 = 2, т.е. дважды
>Приведите код "правильного" зеркалирования таблиц, в двух разных БД! что именно непонятно в [2]? либо включайте мозг, либо $100
-
> Вы каждый раз ходите по всей таблице, а зачем? если вам > надо только то что изменилось с предыдущего раза?
Да, но как я сделаю запрос из одной БД в другую, чтобы выбрать записи только те которых нет в этой? Firebird такого не позволяет вроде. Через Execute statement, используя ON EXTERNAL <строка соединения с другой БД> WITH AUTONOMOUS TRANSACTION AS USER 'sysdba' PASSWORD 'masterkey' я могу выбрать записи, но как я добавлю к этому запросу проверку типа not exists в другой БД? потому и приходится проходится по всей выборке.
> Кщд © (14.10.15 06:26) [8] 1. >EXECUTE STATEMENT ('select ID,NUMBER,PAGENUM,HEADER,STATUS from stati') это полный проход по таблице в главной БД т.е. Вы УЖЕ выбрали все данные из главной
2. >Execute statement ('select count(r.id) from stati r where r.id=?')(:ID) это ещё один проход по таблице из главной
Ну дык, в первом цикле я проверяю ест ли запись из главной БД в подчиненной и если её нет. то добавляю. А во втором, я прохожусь по записям подчиненной и проверяю её наличие в главной, и если её нет, то удаляю. Как я по вашему это запихну в один цикл? например в главной БД в таблице есть записи с ID = 1,2,3,4,5 в подчиненной есть с ID = 1,2,4,5,6,7 в первом цикле, невозможно найти записи подчиненной таблицы с ID 6,7 которые необходимо удалить, т.к. на каждом шаге цикла мы получим записи с ID 1,2,3,4,5 но ни как не узнаем о существовании с ID 6,7 т.к. в главной таблице их просто нет!
> что именно непонятно в [2]?
Вы видимо плохо прочитали ответ >>Копировать 9млн записей во временную таблицу, это не быстрее, поверьте! первичное копирование из главной в подчиненную (т.е. первый цикл ХП), заняло более 15 часов!!!
В предлагаете скопировать 9 млн записей из главной БД в подчиненную в течении 15 часов, а потом конечно выполнить два запроса типа: insert into stati select t.* from stati_temp t where not exists (select k.id from stati k where k.id=t.id) и второй delete from stati where not exists (select k.id from stati_temp k where r.id=id)
или у вас есть способ быстрого копирования таблицы из одной БД в другую? это не Oravle с его tablespaces, и не MySQL, это firebird. В firebird нет варианта select t.*,k.* from bd1.stati t, bd2.stati k where t.id=k.id
> либо включайте мозг, либо $100
алаверды - внимательнее читайте вопрос.
-
>ford © (14.10.15 10:56) [9] в первом посте Вы утверждали, что "т.к. обычно выполнение занимало максимум минут 15-20."
затем: " первичное копирование из главной в подчиненную (т.е. первый цикл ХП), заняло более 15 часов!!!"
где правда?
1. читать вы не умеете; 2. понимать прочитанное не способны; 3. минимальной квалификацией (судя по приведенному коду) для работы с БД не обладаете. => наймите программиста
поскорее давайте мне, пожалуйста, $100, и напишу код, который сделает нужные Вам insert/delete в подчиненной таблице за так желаемые Вами "15-20мин"
-
> где правда?
нда...., поясняю Вам, что такое первичное копирование: это когда мы выполняем процедуру копирования в первый раз, т.е. таблица-приемник пуста! и туда загоняются 9млн. записей. Этот процесс выполняется более 15 часов. Далее, если внимательно смотрели код, который я выкладываю, то могли заметить, что там стоит условие, так вот, при последующем запуске процедуры, копируется не 9млн. записей, а только те, которые внесли после первичного запуска. Вот второй и последующие разы, время копирования мин. 15-20.
> 3. минимальной квалификацией (судя по приведенному коду) > для работы с БД не обладаете. > => наймите программиста поскорее давайте мне, пожалуйста, $100, и напишу код, который сделает нужные Вам insert/delete в подчиненной таблице за так желаемые Вами "15-20мин"
алаверды - если Вы даже не читаете вопрос и не можете вникнуть в код, то какие 100$? Вам, судя по всему, еще учиться и учиться, а пока Ваш уровень это Hello world на VBA
-
> Да, но как я сделаю запрос из одной БД в другую, чтобы выбрать > записи только те которых нет в этой? При помощи установки соответствующих условий, очевидно.
-
> При помощи установки соответствующих условий, очевидно.
В условиях данной задачи, какие условия я могу поставить для execute statement? Учитывая что, выполняется запрос в другой БД. Т.е. ХП находится в базе '192.168.0.250:otdel', а запрос к базе '192.168.0.254:dummy' FOR EXECUTE STATEMENT ('select ID,NUMBER,PAGENUM,HEADER,STATUS from stati') ON EXTERNAL '192.168.0.254:dummy' WITH AUTONOMOUS TRANSACTION AS USER 'sysdba' PASSWORD 'masterkey' INTO :ID,:NUMBER,:PAGENUM,:HEADER,:STATUS DO if (not exists(select t.id from stati t where t.id=:ID)) Then insert into stati (ID,NUMBER,PAGENUM,HEADER,STATUS) values (:ID,:NUMBER,:PAGENUM,:HEADER,:STATUS);
т.е. каким образом к запросу EXECUTE STATEMENT ('select ID,NUMBER,PAGENUM,HEADER,STATUS from stati') , Вы собираетесь указать список записей, которые выбирать не надо? Если вы не в курсе, что такое execute statement, то вот ссылка на справочник http://firebirdsql.su/doku.php?id=execute_statementРебята ухты и Кщд, если Вы не знаете, то не пишите ерунды и общих фраз. Если просто хотите денег за ответы, то Вы не на том форуме пасетесь.
-
>ford © (14.10.15 15:12) [13] желаю счастья!))
-
> Кщд © (14.10.15 15:25) [14]
И Вам, не хворать :)
-
нов от тут вы ставите условия :
> Execute statement ('select count(r.id) from stati r where > r.id=?')(:ID) или в чем проблема? не знаете что поставить, изучайте свою структуру делайте изменения добивайтесь результата.
-
>ухты © (14.10.15 16:02) [16] бесполезняк это всё) пациент даже не понимает, что здесь: EXECUTE STATEMENT ('select ID,NUMBER,PAGENUM,HEADER,STATUS from stati')
он каждый раз (при каждом запуске) получает все 9 000 000 записей в подчиненную БД из главной
про дальнейшую оптимизацию (триггеры на изменение в главной БД и подчиненной со складированием ID измененных записей в спец. таблицы с тем, чтобы не ворочать 9*10^6 записей каждый раз) и говорить нечего
пациент скорее мертв, чем наоборот))
-
> про дальнейшую оптимизацию (триггеры на изменение в главной > БД и подчиненной со складированием ID измененных записей > в спец. таблицы с тем, чтобы не ворочать 9*10^6 записей > каждый раз) и говорить нечего
Прикнь, знаю и использую :) Но, есть задача, которая описанна в вопросе и её решение. Медленное, но решение. К сожалению, Кщд, как я понял из ваших ответов, Ваш уровень знания не позволяет оптимизировань её решение. Говорить пустые, общие фразы, это ваш конек :)
-
>ford © (16.10.15 10:44) [18] >К сожалению, Кщд, как я понял из ваших ответов, Ваш уровень знания не позволяет оптимизировань её решение. >Говорить пустые, общие фразы, это ваш конек :) увы, это так((( но я азартен, черт подери! давайте условимся так: 1. за сутки переучиваюсь с VBA для Excel на PSQL; 2. пишу и выкладываю код, выполняющий Вашу задачу (в рамках озвученных в этой ветке условий), здесь; 3. если - вдруг! - мой код сработает, вы высылаете мне $200. если, что верно с вероятностью 99.9997%, код не срабатывает, то я высылаю вам $300 (даже $315 - именно столько завалялось у меня в электронном кошельке).
легкие деньги, соглашайтесь!)))
-
Всегда умиляли заявления про 100500 мильёнов записей в таблице. 1. Если ты имеешь права, то меняй структуру и логику работы. Пиши весь день ID в "ежедневную" таблицу, а потом, в конце дня, копируй эту маленькую таблицу в "подчинённую". В подчинённой таблице для "местных" действий используй свою таблицу ID, которые при копировании удалятся. 2.Если никаких прав у тебя нет и если уж тебе ПОСТОЯННО необходимо переливать такую "большую" таблицу, то есть огромное подозрение, что простой "бэкап" здесь, пересылка и "ресторе" там будет намного быстрее и надёжнее твоих изысков.
-
Удалено модератором
|