Совет ваш нужен. На удаленном объекте есть база данных Firebird. В офисе развернут SQL Server 2000, на котором создал базу данных, по структуре практически совпадающую с firebird-овской (вместо timestamp - datetime, varchar - nvarchar, float - money, smallint - bit, blob - image). Так вот, мне необходимо вносить изменения в БД офиса из БД объекта, то есть иметь в офисе актуальные данные.
Написал небольшой проект, периодически производящий бэкап, архивацию и разбивку на небольшие файлы базы на объекте (связь неустойчивая, поэтому проще качать данные небольшими порциями). В офисе файлы склеиваются, восстанавливается исходная БД firebird. Это все уже реализовано.
И вот тут дилемма возникла. Как бы мне унифицировать процедуру чтения данных из таблиц firebird и записи в таблицы sql server? Как-то некрасиво вручную перебирать все таблицы и имена полей.
Использую компоненты: TZConnection, TZQuery, TADOConnection, TADOQuery.
Использование SQL Server'a обязательно - пожелание админов.
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
14-05-2010 00:11 | Сообщение от автора вопроса
2 simon.kms: Неа, не получится. По крайней мере мне так думается. Хотя знатокам FB видней.
У меня другая проблема возникла: не получается импортировать данные, если в поле типа BLOB имеются данные, отличные от NULL. Так что в своей статье я был неправ касательно дружбы BLOB и IMAGE. Что только не пробовал - не получается. А в BLOB записываются snapshot'ы с камеры наблюдения AXIS в момент, когда на весы КТП что-то заехало (превышен некий порог веса). Затем в офисе можно визуально удостовериться, что въезжала/выезжала именно та машина, которая указана в накладной или никакого левака со склада вывезено не было.
На данный момент между удаленным объектом и офисом установили стабильную высокоскоростную связь, так что данные теперь сохраняю не на объекте в FB с последующим импортом на сервер, а пишу напрямую на сервер офиса (MSSQL).
13-04-2010 23:36 | Вопрос к автору: запрос дополнительной информации
В-общем, довольно подробно описан механизм переноса информацию в одну сторону: из FB в MSSQL. Сразу же подумалось: а в обратную сторону переливать данные получиться? Могу ли я с помощью описанного варианта увидеть, к примеру, результаты запроса из FB к таблицам в MSSQL?
Время составило 2 секунды! Это что такое может быть: данные где-то кешируются или ExecProc не ждет окончания выполнения процедуры? Или может так и должно быть?
ExecProc не ждет окончания процедуры только при асинхронном выполнении. Думаю, это не твой случай. А 2 секунды для импорта небольших таблиц - нормальный результат.
procedure TForm1.sButton1Click(Sender: TObject);
var t1,t2:TDateTime; sec:integer;
begin
try
ADOConnection2.Connected:=true;
t1:=Now;
ADOStoredProc2.ProcedureName:='ImportFBData';
ADOStoredProc2.Prepared:=true;
ADOStoredProc2.ExecProc;
t2:=Now;
sec:=SecondsBetween(t2,t1);
ShowMessage('Время операции: '+inttostr(sec)+' сек.')
finally
ADOConnection2.Connected:=false;
end
end;
Время составило 2 секунды! Это что такое может быть: данные где-то кешируются или ExecProc не ждет окончания выполнения процедуры?
Или может так и должно быть? Если так, то УРА! Green, Noskov огромное спасибо.
Green, ты даже не представляешь как я тебе благодарен! Мало того, что сэкономил мне кучу времени, так еще и ткнул меня носом и помог разобраться в новом для меня направлении. Еще раз спасибо!
Noskov, спасибо. Попробую.
Кстати, интересная особенность! Я запускал процедуру ImportFBData прямо в редакторе процедуры (EMS SQL Manager 2005), в результате чего время составило около 6 минут. Попробовал выполнить команду exec ImportFBData в окне SQL Script - отработало за ... 9 секунд %(
Может подскажете, как бы мне оптимизировать мои процедуры? Самая объемная таблица - RECORD, в ней около 500 записей. Так вот, время на импорт всей БД составило около 6 минут :| Как-то чересчур уж многовато.
6 минут на 500 записей действительно многовато. 6 секунд - нормально :)
Сначала надо разобраться в чем тормоза - во вставке или в чтении из FB. Подозреваю, что проблема в работе через OpenRowSet и через провайдера FB. Тогда ускорить вряд ли получится. Я работал через OpenRowSet, но с Акцессом, а это все-таки продукт Майкрософта. И запуска DTS он не требовал. Попробуй просто выполнить SELECT без вставки - сколько времени он будет выполняться? И посмотри - сильно ли отличается время SELECT'а для разных таблиц?
Кстати, еще раз просмотрел твой пост от 23-07-2009 07:29
Идею ты предложил хорошую, да вот тут UPDATE СтараяТаблица SET ... FROM НоваяТаблица WHERE СтараяТаблица.ID = НоваяТаблица.ID мне придется перебирать все имена столбцов. Изучил описание UPDATE - вроде как все столбцы скопом без указания имени обновить нельзя. Может есть еще какой способ?
Green. У меня еще вопрос. Я в SQL не особо силён, изучаю на практике. Может подскажете, как бы мне оптимизировать мои процедуры? Самая объемная таблица - RECORD, в ней около 500 записей. Так вот, время на импорт всей БД составило около 6 минут :| Как-то чересчур уж многовато.
Я пошел по более простому пути. Структура БД не сложная, особо большие скорости не нужны, поэтому от внешних ключей отказался.
Вот, что у меня получилось:
CREATE PROCEDURE ImportFBData
AS
BEGIN
declare @s1 varchar(30)
declare @s2 varchar(255)
set @s1='LCPI.IBProvider.3.Free'
set @s2='Password=***;Persist Security Info=True;User ID=***;'+
'Location=D:\Projects\AccessScale\db\SCALE.FDB;ctype=ASCII;dialect=3;'+
'auto_commit=True;support_odbc_query=False;unicode_mode=False;'+
'unicode_stmt=False;dbclient_library=gds32.dll;dbclient_type=fb'
CREATE PROCEDURE ImportFBTable
@Prov nvarchar(30), @ConStr nvarchar(255), @Table nvarchar(30)
AS
BEGIN
exec('delete from '+@Table)
exec('insert into '+@Table+' select * from OpenRowSet('''+@Prov+''','''+@ConStr+''',''select * from '+@Table+''')')
END
Все просто. Сначала delete from Table, а затем insert бла-бла-бла )))
Ну, это просто, если в БД нет внешних ключей.
А если есть, то тоже не очень сложно:
UPDATE СтараяТаблица SET ... FROM НоваяТаблица WHERE СтараяТаблица.ID = НоваяТаблица.ID
INSERT INTO СтараяТаблица SELECT НоваяТаблица.* FROM НоваяТаблица LEFT JOIN СтараяТаблица ON НоваяТаблица.ID = СтараяТаблица.ID WHERE СтараяТаблица.ID IS NULL
Надеюсь, не нужно говорить, что вставку теперь можно сделать одной командой?
В том то и дело, что не совсем все так просто. Мне нужно не только вставлять данные, но и обновлять существующие... Вот, копаю sql.ru в поиске решения. А может есть идея?
Была выключена. Пытаюсь запустить - выдает ошибку. В системном журнале пишет: Служба "Координатор распределенных транзакций" завершена из-за внутренней ошибки 3221229584.
Неверной дорогой идете, товарищ! :)
Гм, понял. Я собственно думал клиента написать с двумя TADOConnection и перекидывать данные из одного в другой, заодно и проверять: создать новую запись или обновить существующую.
В EMS SQL Manager 2005 замутил следующее:
select* from OpenRowSet('LCPI.IBProvider.3.Free','Password=***;Persist Security Info=True;User ID=***;Location=D:\Projects\AccessScale\db\SCALE.FDB;ctype=ASCII;dialect=3;auto_commit=True;support_odbc_query=False;unicode_mode=False;unicode_stmt=False;dbclient_library=gds32.dll;dbclient_type=fb','select * from CARS')
На что получил по голове:
MSDTC on server 'ACHMIL_WS' is unavailable.
(ACHMIL_WS - имя компьютера)
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.