Форум: "Базы";
Текущий архив: 2004.06.27;
Скачать: [xml.tar.bz2];
ВнизЗапрос к двум БД InterBase Найти похожие ветки
← →
Demon (2004-06-02 18:13) [0]Привет Всем Знатокам!
Проблема у меня заключается в следующем:
есть 2 базы идентичные по структуре : 1 - база архив, 2 - рабочая (главная).
В конце какого-то периода данные из базы 2 переносятся в базу 1.
Теперь надо сделать так, чтоб можно было сделать запрос к двум базам.
Подскажите как можно это реализовать и возможно ли?
← →
jack128 © (2004-06-02 18:30) [1]
> Теперь надо сделать так, чтоб можно было сделать запрос
> к двум базам.
никак. Покрайней мере не на компонентах прямого доступа. Хотя может какие нить прослойки а-ля ADO это могут...
← →
sniknik © (2004-06-02 18:50) [2]> Хотя может какие нить прослойки а-ля ADO это могут...
знаю единственный способ, подключится к MSSQL и уже в нем через OPENROWSET - OLE DB провайдера к IB (нужно поставить) сделать запрос, с линками к обоим базам. (не факт что получится)
аналогично можно бы и в access но там только один внешний линк к запросе позволяется... (можно подключить линкованые таблицы "стационарно" но и тут не факт что получится)
а вот BDE должен справится.
проше наверное делать всетаки в разных запросах с разными конектами а если нужны обьедененные данные то делать это на клиенте.
← →
Romkin © (2004-06-02 19:02) [3]>а вот BDE должен справится.
Угу, перекачав все таблицы запроса на клиентскую часть, и только потом сделав запрос. Стоит ли?
← →
Demon (2004-06-02 19:07) [4]> проше наверное делать всетаки в разных запросах с разными конектами а если нужны обьедененные данные то делать это на клиенте
А неподскажеш как объеденить эти данные в один кусок?
← →
jack128 © (2004-06-02 19:09) [5]
> А неподскажеш как объеденить эти данные в один кусок?
А что ты называешь одним куском?
← →
Demon (2004-06-02 19:15) [6](Набор данных 1 базы) + (Набор данных 2 базы) = кусок.
Чтоб потом по этому объединённому набору данных (т.е. кусок) сделать отчёт.
← →
jack128 © (2004-06-02 19:32) [7]у тебя в чем проблема то? Получить > Набор данных 1 базы или может затруднения с > Набором данных 2 базы ? ;-) Или ты без единого Dataset"a не можешь отчет построить?
Ладно пример:
положим в одной базе есть таблица customers, к которой в часности есть id города по которому проживает каждый из наших кастомеров. название города храниться в другой базе..
// sql1, sql2 - TIBSql, sql1 подключен к одной базе, sql2 - к другой
sql1.SQL.Text := "select city_id from customers where customer_name like ""Иван%""";
sql1.ExecSQl;
WhereClause := "";
while not sql1.EOF do
begin
WhereClause := WhereClause + sql.FieldByName("city_id").AsString + ",";
sql1.Next;
end;
sql1.Close;
if WhereClause = "" then Exit;
WhereCaluse := "where city_id in (" + copy(WhereClause, 1, Length(WhereClause) - 1) + ")";
sql2.SQL.Text := "select city_name from cities " + WhereClause;
sql2.ExecQuery;
while not sql2.EOF do
begin
CitiesStringList.Add(sql2.FieldByName("city_name").AsString);
sql2.Close;
end;
sql.Close;
// в результате получил список городов
← →
sniknik © (2004-06-02 19:33) [8]сливай все в clientdataset к примеру. с одной базы можно через провайдер данных в него закачать, с другой придется добавлять позаписьно открыв в другом датасете (может и есть способ массового дабавления не тронув имеюшиеся данные но я его не знаю, и искать влом).
а уже с clientdataset-а отчет сделать, не труднее чем сдругого датасета.
← →
sniknik © (2004-06-02 19:36) [9]jack128 © (02.06.04 19:32) [7]
обьеденение в StringList будет дольше чем рекордсет. если обьемы отчета приличные то нежелательно.
← →
jack128 © (2004-06-02 19:46) [10]
> обьеденение в StringList будет дольше чем рекордсет
это почему?
← →
sniknik © (2004-06-02 19:56) [11]> это почему?
по личному опыту. ;о)) и потом если дополнять рекордсет данными второго, понадобится добавить только половину не так ли? даже не учитывая остального... быстрее.
было бы еще быстрее если найти способ массового обьеденения рекордсетов.
← →
jack128 © (2004-06-02 20:07) [12]
> по личному опыту. ;о))
:-)
> и потом если дополнять рекордсет данными второго, понадобится
> добавить только половину не так ли?
не понял, что имеется в виду. В смысле, что если нужен union, то из часть НД из первой базы мы получаем автоматом и остается только то что нужно взять из второй базы? А чем стринг лист отличается? Кодирования разве что побольше.
> даже не учитывая остального... быстрее.
ну если у тя получалось быстрее, то мне сложно что то возразить потому что я таких эксперементов не проводил, но по логике лист ДОЛЖЕН быть быстрее.. Уж не знаю, что Borland в мидасе замутили чтобы так получилось, что датасет оказался быстрее..
← →
sniknik © (2004-06-02 22:11) [13]> не понял, что имеется в виду. В смысле, что если нужен union, то из часть НД из первой базы мы получаем автоматом и остается только то что нужно взять из второй базы? А чем стринг лист отличается? Кодирования разве что побольше.
ну да union (во всяком случае так понял именно это нужно). именно
в стринг лист ты добавляеш в 2 прохода, по первому рекорсету после по второму, а с рекордсетами в полученый первый дабавить второй, 1 проход, только по второму рекордсету, и получаем нужное в первом.
> но по логике лист ДОЛЖЕН быть быстрее..
думаеш? чтото у тебя логика хромает, рекордсеты именно для работы с данными делались причем с большими обьемами, а слинг лист... ну у него даже индексов нет, все операции перебором (наверное).
впрочем чего спорить, написать тест дело получаса, возьмешся? после сравним результат (в одного ломает).
кстати стринг лист я не тестил, так что все честно, результат заранее не знаю, могу только предположить.
← →
jack128 © (2004-06-03 07:28) [14]вобщем навоял я тестик..Правда с КлиентДатаСет дело имею впервые, так что проврь, пжлста ;-)
Итак есть база с табличкой в 10000 записей, я просто сделал её копию подключил к IbDatabase1 и IbDatabase2. На каждый IbDatabase есть своя транзакция IbTransaction1 и IbTransaction2. запрос прост как валенок "select NAME from ADDRESSES"
// код для ibsql + stringlist
procedure TForm1.Button1Click(Sender: TObject);
var
sl: TStringList;
t: Cardinal;
begin
t := GetTickCount;
sl := TStringList.Create;
try
sl.Capacity := 100;
ibsql1.Database := IbDataBase1;
ibsql1.Transaction := IbTransaction1;
ibsql1.ExecQuery;
while not ibsql1.Eof do
begin
sl.Add(ibsql1.FieldByName("name").AsString);
ibsql1.next;
end;
ibsql1.Close;
ibsql1.Database := IbDataBase1;
ibsql1.Transaction := IbTransaction1;
ibsql1.ExecQuery;
while not ibsql1.Eof do
begin
sl.Add(ibsql1.FieldByName("name").AsString);
ibsql1.next;
end;
ibsql1.Close;
finally
sl.Free;
end;
Caption := IntToStr(GetTickCount - t);
end;
// код для ClientDataSet
procedure TForm1.Button2Click(Sender: TObject);
var
t: Cardinal;
begin
t := GetTickCount;
IbDataSet1.Database := IbDataBase1;
IbDataSet1.Transaction := IbTransaction1;
DataSetProvider1.DataSet := IbDataSet1;
ClientDataSet1.ProviderName := DataSetProvider1.Name;
ClientDataSet1.Active := True;
ClientDataSet1.Last;
ClientDataSet1.ProviderName := "";
IbDataSet1.Close;
IbDataSet1.Database := IbDataBase2;
IbDataSet1.Transaction := IbTransaction2;
IbDataSet1.Open;
while not IbDataSet1.eof do
begin
ClientDataSet1.Append;
ClientDataSet1.FieldByName("NAME").AsString :=
IbDataSet1.FieldByName("NAME").AsString;
ClientDataSet1.Post;
IbDataSet1.Next;
end;
IbDataSet1.Close;
Caption := IntToStr(GetTickCount - t);
end;
результаты для листа около 2,6 сек
для клиент датасет порядка 8-9 секунд!!
причем если и первой базы данные заливатся приметно одинаково быстро (для stringlist порядка 1,2 сек, для ClientDS - 1,4 где то 10-15% отставания вполне компенсируется удобством использования), но заливка данных из второй базы, как видно все очень сильно портит. цикл while not IbDataSet1.eof do - это просто катастрофа.. Может есть какой нить способ залить данные в ClientDS? Если нет, тот все очень плохо ;-)
← →
sniknik © (2004-06-03 08:19) [15]вроде верно все, на работе будет время тоже проверю, динственное если у тебя ClientDataSet1 связан с какимнибудь контролом (гридом) то лутше поставить перед операциями
ClientDataSet1.DisableConstraints
и
ClientDataSet1.EnableConstraints
в конце.
преобразование имени к индексу (определение смещения) FieldByName тоже немного тормозит операцию (во втором случае 2 таких вызова).
для стринг грида тоже не помешает
list.BeginUpdate;
list.EndUpdate
но тут по коду видно это не влияет (ты его сам создаеш и он не входит ни в какой визуальный компонент)
в общем гдето к обеду напишу результат своего теста (буду делать с dbExpress они мне кажутся попроще в использовании).
← →
sniknik © (2004-06-03 12:05) [16]нет приличной по обьему базы IB ;( взял привычный для себя mdb (их у меня много выляется... ;о)
но это в принципе неважно меряем то время добавления в ClientDataSet и стринг лист, а не компонент/движок.
вообще да теперь согласен, стринг лист в этом случае быстрее (даже то что с ним 2 цикла вместо одного не спасает), вот если добавлять переобразования (типы в датасетах не только строки а и float/datatime) то результаты одинаковы (приблизительно) и даже датасет выигрывает.
и у меня не получилось таких впечатляющих отличий (2,6 сек против 8-9 секунд (!!))
у меня разница составила гдето секунду, на переносе
т.е. добавление и первого и второго клиеттского рекордсета в стринг лист 2,25/2,46 сек
добовление к первому рекордсету второго 3,25/3,33сек
(мин. и макс. полученные результаты, выполнял по 6 раз всего в таблице (я чтоб не заморачиватся 2 коннекта к одной базе сделал) 13511 записей)
если брать полное время с получением данных(открытием датасетов) то оно составило гдето 10,4 и 11,4 сек
модуль как тестировал (для каждого теста перезапускать программу! иначе неправильно, 1й лабел - общее время 2 - время цикла 3 - всего строк)
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Grids, DBGrids, DB, Provider, DBClient, ADODB;
type
TForm1 = class(TForm)
ADOConnection1: TADOConnection;
ADODataSet1: TADODataSet;
ClientDataSet1: TClientDataSet;
DataSetProvider1: TDataSetProvider;
ADODataSet2: TADODataSet;
DataSetProvider2: TDataSetProvider;
ClientDataSet2: TClientDataSet;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
ListBox1: TListBox;
Button1: TButton;
Button2: TButton;
Label1: TLabel;
ADOConnection2: TADOConnection;
Label2: TLabel;
Label3: TLabel;
CheckBox1: TCheckBox;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
MainSaveTime, WhileSaveTime: TDateTime;
st: string;
fNum1, fName1, fNum2, fName2: TField;
begin
MainSaveTime:= Now;
Label1.Caption:= "0:00:000";
Label1.Caption:= "0";
ClientDataSet1.DisableControls;
ClientDataSet2.DisableControls;
if CheckBox1.Checked then begin
ClientDataSet1.PacketRecords:= 300;
ClientDataSet2.PacketRecords:= 300;
end;
ListBox1.Items.BeginUpdate;
ClientDataSet1.Open;
ClientDataSet2.Open;
ClientDataSet1.LogChanges:= false;
ClientDataSet2.LogChanges:= false;
fNum1:= ClientDataSet1.FieldByName("ARTICUL");
fName1:= ClientDataSet1.FieldByName("NAME");
fNum2:= ClientDataSet2.FieldByName("ARTICUL");
fName2:= ClientDataSet2.FieldByName("NAME");
WhileSaveTime:= Now;
while not ClientDataSet2.Eof do begin
ClientDataSet1.Append;
fNum1.AsString:= fNum2.AsString;
fName1.AsString:= fName2.AsString;
ClientDataSet2.Next;
end;
if (ClientDataSet1.State = dsEdit) or (ClientDataSet1.State = dsInsert) then ClientDataSet1.Post;
DateTimeToString(st, "n:ss:zzz", Now - WhileSaveTime);
Label2.Caption:= st;
ListBox1.Items.EndUpdate;
ClientDataSet2.EnableControls;
ClientDataSet1.EnableControls;
DateTimeToString(st, "n:ss:zzz", Now - MainSaveTime);
Label1.Caption:= st;
Label3.Caption:= IntToStr(ClientDataSet1.RecordCount);
end;
procedure TForm1.Button2Click(Sender: TObject);
var
MainSaveTime, WhileSaveTime: TDateTime;
st: string;
fNum1, fName1, fNum2, fName2: TField;
begin
MainSaveTime:= Now;
Label1.Caption:= "0:00:000";
Label1.Caption:= "0";
ClientDataSet1.DisableControls;
ClientDataSet2.DisableControls;
if CheckBox1.Checked then begin
ClientDataSet1.PacketRecords:= 300;
ClientDataSet2.PacketRecords:= 300;
end;
ListBox1.Items.BeginUpdate;
ClientDataSet1.Open;
ClientDataSet2.Open;
ClientDataSet1.LogChanges:= false;
ClientDataSet2.LogChanges:= false;
fNum1:= ClientDataSet1.FieldByName("ARTICUL");
fName1:= ClientDataSet1.FieldByName("NAME");
fNum2:= ClientDataSet2.FieldByName("ARTICUL");
fName2:= ClientDataSet2.FieldByName("NAME");
WhileSaveTime:= Now;
while not ClientDataSet1.Eof do begin
ListBox1.Items.Add(fNum1.AsString + fName1.AsString);
ClientDataSet1.Next;
end;
while not ClientDataSet2.Eof do begin
ListBox1.Items.Add(fNum2.AsString + fName2.AsString);
ClientDataSet2.Next;
end;
if (ClientDataSet1.State = dsEdit) or (ClientDataSet1.State = dsInsert) then ClientDataSet1.Post;
DateTimeToString(st, "n:ss:zzz", Now - WhileSaveTime);
Label2.Caption:= st;
ListBox1.Items.EndUpdate;
ClientDataSet2.EnableControls;
ClientDataSet1.EnableControls;
DateTimeToString(st, "n:ss:zzz", Now - MainSaveTime);
Label1.Caption:= st;
Label3.Caption:= IntToStr(ListBox1.Count);
end;
end.
← →
sniknik © (2004-06-03 12:06) [17]и dfm чтобы собрать програмку не напрягаясь ;о)
object Form1: TForm1
Left = 264
Top = 107
Width = 691
Height = 335
Caption = "Form1"
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = "MS Sans Serif"
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 168
Top = 8
Width = 32
Height = 13
Caption = "Label1"
end
object Label2: TLabel
Left = 168
Top = 24
Width = 32
Height = 13
Caption = "Label2"
end
object Label3: TLabel
Left = 168
Top = 38
Width = 32
Height = 13
Caption = "Label3"
end
object DBGrid1: TDBGrid
Left = 0
Top = 88
Width = 369
Height = 217
DataSource = DataSource1
TabOrder = 0
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = "MS Sans Serif"
TitleFont.Style = []
end
object ListBox1: TListBox
Left = 376
Top = 88
Width = 297
Height = 217
ItemHeight = 13
TabOrder = 1
end
object Button1: TButton
Left = 288
Top = 56
Width = 75
Height = 25
Caption = "Button1"
TabOrder = 2
OnClick = Button1Click
end
object Button2: TButton
Left = 600
Top = 56
Width = 75
Height = 25
Caption = "Button2"
TabOrder = 3
OnClick = Button2Click
end
object CheckBox1: TCheckBox
Left = 8
Top = 8
Width = 137
Height = 17
Caption = "Use PacketRecords"
TabOrder = 4
end
object ADOConnection1: TADOConnection
ConnectionString =
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\DB\pos.mdb;Persi" +
"st Security Info=False"
LoginPrompt = False
Provider = "Microsoft.Jet.OLEDB.4.0"
Left = 16
Top = 136
end
object ADODataSet1: TADODataSet
Connection = ADOConnection1
CommandText = "SELECT * FROM KKMGOODS"
Parameters = <>
Left = 56
Top = 136
end
object ClientDataSet1: TClientDataSet
Aggregates = <>
DisableStringTrim = True
Params = <>
ProviderName = "DataSetProvider1"
Left = 136
Top = 136
end
object DataSetProvider1: TDataSetProvider
DataSet = ADODataSet1
Left = 96
Top = 136
end
object ADODataSet2: TADODataSet
Connection = ADOConnection2
CommandText = "SELECT * FROM KKMGOODS"
Parameters = <>
Left = 56
Top = 176
end
object DataSetProvider2: TDataSetProvider
DataSet = ADODataSet2
Left = 96
Top = 176
end
object ClientDataSet2: TClientDataSet
Aggregates = <>
DisableStringTrim = True
Params = <>
ProviderName = "DataSetProvider2"
Left = 136
Top = 176
end
object DataSource1: TDataSource
DataSet = ClientDataSet1
Left = 184
Top = 136
end
object ADOConnection2: TADOConnection
ConnectionString =
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\DB\pos.mdb;Persi" +
"st Security Info=False"
LoginPrompt = False
Provider = "Microsoft.Jet.OLEDB.4.0"
Left = 16
Top = 176
end
end
p.s. если поставить галочку на чекбокс ситуация резко меняется, датасет становится быстрее но общее время увеличивается, нехорошо. ;о)
← →
Vlad © (2004-06-03 12:17) [18]http://www.ibase.ru/devinfo/ibfaq.htm#1.34
Вкратце так:
Берем БДЕ, настраиваем два алиаса, один- на одну базу, другой на другую. Затем делаем гетерогенный SQL запрос к двум базам.
Синтаксис гетерогенных запросов описан в справке по LocalSql
← →
jack128 © (2004-06-03 12:36) [19]
> while not ClientDataSet2.Eof do begin
> ClientDataSet1.Append;
> fNum1.AsString:= fNum2.AsString;
> fName1.AsString:= fName2.AsString;
> ClientDataSet2.Next;
> end;
> if (ClientDataSet1.State = dsEdit) or (ClientDataSet1.State
> = dsInsert) then ClientDataSet1.Post;
А почему Post вне цикла ? ты, получается, преносишь в ClientDataSet1 только одну запись..
← →
jack128 © (2004-06-03 12:40) [20]
> Берем БДЕ, настраиваем два алиаса, один- на одну базу, другой
> на другую. Затем делаем гетерогенный SQL запрос к двум базам.
> Синтаксис гетерогенных запросов описан в справке по LocalSql
cм [3]
← →
sniknik © (2004-06-03 12:41) [21]> А почему Post вне цикла ? ты, получается, преносишь в ClientDataSet1 только одну запись.
Append неявно вызывает Pos второй раз он просто лишний, а вот в конце может понадобится если конечно рекордсет был не пустои и Append хоть раз отработал.
← →
jack128 © (2004-06-03 12:57) [22]
> Append неявно вызывает Pos
не знал, думал ексептион будет -)
знаешь, попробуй добавлять записи в лист непосредственно из ADODataSet"ов, тогда наверно разница ощутима будет..
Хотя как знать..
← →
Vlad © (2004-06-03 13:18) [23]
> jack128 © (03.06.04 12:40) [20]
> cм [3]
и что смотреть ?
Автор спрашивал как сделать запрос к двум разным базам.
Можешь предложить другие варианты ?
К слову говоря, возможно выкачка всех таблиц запроса на клиента не так уж и критична для автора, мы же не знаем.
← →
jack128 © (2004-06-03 13:34) [24]
> и что смотреть ?
на то что
а) этот способ уже был дан
б) были указаны недостатки это способа
в) после описания недостатков автор видимо счел эти недостатки сесьма серьёзными, поскольку спросил :
> > проше наверное делать всетаки в разных запросах с разными
> конектами а если нужны обьедененные данные то делать это
> на клиенте
>
> А неподскажеш как объеденить эти данные в один кусок?
вобщем предложено два способа, любой из них в сети или/и на больших объемах будет ЯВНО быстрее BDE, а на локальном компе надо смотреть..
> sniknik ©
Не знаю,что и думать...Разница уж очень большая в наших эксперементах..На выходных нужно базу на Access"e посмотреть, что у меня получиться.
Кстати для генерации тестовых данных для IB можно использовать IbExpert.
← →
sniknik © (2004-06-03 14:47) [25]> знаешь, попробуй добавлять записи в лист непосредственно из ADODataSet"ов, тогда наверно разница ощутима будет..
наверняка, основное время идет на получение через провайдер, а по другому нельзя, в условии мидас, т.е. надо полученные на клиента данные обрабатывать из клиентских датасетов (хотя почему нельзя(?) смотря как сервер сделаеш, можно и там сливать но тогда смысл сравнений теряется ;) передавать все одно датасет придется).
поэтому и сделал дополнительно отчет времени только для перекладывания. и там по чекбоксу когда размер пакета задается начинается получение порциями (почти серверный курсор) время резко меняется на перекладывание приходится большая часть... (оно и понятно данные докачиваются в процессе)
> Не знаю,что и думать...Разница уж очень большая в наших эксперементах..
а ты как тестил, нажал одну кнопочку с базой после другую с стринг листом? тогда будет ошибочный тест.
надо при каждом тесте перезапускать программу, запустил посмотрел с базой, вышел запустил смотриш стринг лист.
исключить возможность всяких кешей буферов и т.д.
> Кстати для генерации тестовых данных для IB можно использовать IbExpert.
не смотрел, хотя он у меня и есть. проверил простым запросом (insert into t1 select * from t1) в аксесс срабатывает, в IB нет, ну сразу и взял базу где уже есть прилично записей.
← →
jack128 © (2004-06-03 14:53) [26]
> а ты как тестил, нажал одну кнопочку с базой после другую
> с стринг листом? тогда будет ошибочный тест.
> надо при каждом тесте перезапускать программу, запустил
> посмотрел с базой, вышел запустил смотриш стринг лист.
> исключить возможность всяких кешей буферов и т.д.
Я даже пару раз перезагрузился -) Так что кешей никаких не было. Бред вобщем..Я твой код на выходных тоже погоняю, просто сейчас времени нема с аксесом разбираться..
Страницы: 1 вся ветка
Форум: "Базы";
Текущий архив: 2004.06.27;
Скачать: [xml.tar.bz2];
Память: 0.57 MB
Время: 0.093 c