Dúvida com o ClientDataSet

Delphi

21/11/2006

Seguinte, estou utilizando um ClientDataSet ligado a um Query que realiza uma consulta.

Digamos que eu traga todos os registros da tabela com essa consulta (500 registros) da seguinte forma:

        BuscaCDS.Close;
        QBusca.Close;
        QBusca.SQL.Clear;
        QBusca.SQL.Add(´select e.codigo,e.estoque,itm.itm_descricao, un.medida,  cast(upper(c.descricao) as varchar) as categoria from almoxarifado.estoque e´);
        QBusca.SQL.Add(´join materiais.itens itm on itm.id = e.fk_item´);
        QBusca.SQL.Add(´join almoxarifado.unidades_medidas un on e.fk_unidade = un.id´);
        QBusca.SQL.Add(´join almoxarifado.categorias_materiais c on c.codigo = e.fk_categoria_material´);
        QBusca.SQL.Add(´where e.fk_almoxarifado = :fk_almoxarifado and c.fk_almoxarifado = :fk´);
        QBusca.SQL.Add(´order by e.codigo´);
        QBusca.Params[0].AsInteger := VFk_Almoxarifado;
        QBusca.Params[1].AsInteger := VFk_Almoxarifado;
        BuscaCDs.Open;


A consulta demora mais do que se eu usasse somente o Query. Pelo que parece ao abrir o ClientDataSet ele abre a Query que demora um pouco, depois ele ´copia´ os registros da Query para o ClientDataSet.

Com isso ele demora mais do que com o Query... eu uso essa opção pois eu posso desconectar da base e não ficar com o registro amarrado... enfim... será que existe algo a ser feito em relação a isso... ou é assim mesmo?

Estou usando o PostgreSQL com Zeos.

PS. O ClientDataSet funciona numa boa com o Zeos desde que eu não utilize o PacketRecords


Marcelo_mileris

Marcelo_mileris

Curtidas 0

Respostas

Brunolspp

Brunolspp

21/11/2006

o correto e vc passar os parametros e td mais pelo clientdataset..

vc pode obter mais exemplos e uma apostila q mostra alguams tecnicas de desenvolvimento clientdataset em:
http://cc.borland.com/Author.aspx?ID=795118

Abração


GOSTEI 0
Marcelo_mileris

Marcelo_mileris

21/11/2006

Vc diz utilizar a propriedade CommandText do ClientDataSet?
Isso faz com que a consulta seja realizada diretamente no ClientDataSet e não como eu expliquei no primeiro post?


GOSTEI 0
Brunolspp

Brunolspp

21/11/2006

vc pode usar o comando ate na query, poreme parametrizar e não criar dinamicamente.. ou se criar, fazer o fecth params no clientdataset e executar a passagem de parametros pelo CDS bem como a abertura dos resultados também

Abração


GOSTEI 0
Marcelo_mileris

Marcelo_mileris

21/11/2006

Ok... cheguei ao seguinte código:

        BuscaCDS.Close;
        QBusca.Close;
        QBusca.SQL.Clear;
        QBusca.SQL.Add(´select e.codigo,e.estoque,itm.itm_descricao, un.medida,  cast(upper(c.descricao) as varchar) as categoria from almoxarifado.estoque e´);
        QBusca.SQL.Add(´join materiais.itens itm on itm.id = e.fk_item´);
        QBusca.SQL.Add(´join almoxarifado.unidades_medidas un on e.fk_unidade = un.id´);
        QBusca.SQL.Add(´join almoxarifado.categorias_materiais c on c.codigo = e.fk_categoria_material´);
        QBusca.SQL.Add(´where e.fk_almoxarifado = :fk_almoxarifado and c.fk_almoxarifado = :fk´);
        QBusca.SQL.Add(´order by e.codigo´);
        BuscaCDS.FetchParams;
        BuscaCDS.Params[0].AsInteger := VFk_Almoxarifado;
        BuscaCDS.Params[1].AsInteger := VFk_Almoxarifado;
        BuscaCDS.Open;



Foi dessa forma que vc se referiu?


GOSTEI 0
Brunolspp

Brunolspp

21/11/2006

sim.. a parte final sim..

mas pq vc naum deixa o comando direto na query e so passa os parametros pelo cds, dai é só

BuscaCDS.Close;
BuscaCDS.Params[0].AsInteger := VFk_Almoxarifado;
BuscaCDS.Params[1].AsInteger := VFk_Almoxarifado;
BuscaCDS.Open;

abração


GOSTEI 0
Marcelo_mileris

Marcelo_mileris

21/11/2006

Eu não deixo a instrução direto pois eu monto ela conforme for selecionado a opção de busca... essa instrução é uma delas...

Agradeço a ajuda... realmente ficou um pouco mais rápido o ClientDataSet para trazer os resultados.


GOSTEI 0
Marcelo_mileris

Marcelo_mileris

21/11/2006

Esqueci de perguntar... se eu fizer várias buscas... montando as instruções dinamicamente... eu preciso limpar os parâmetros também... ou não implica em nada???


GOSTEI 0
Titanius

Titanius

21/11/2006

Bem, a principio, quando você muda o CommandText, os parametros são zerados... pelo menos eu nunca precisei limpa-los :D

[]s


GOSTEI 0
Brunolspp

Brunolspp

21/11/2006

no clientdataset é preciso limpar os parametros ou fazer o fetchparams de novo..

para construção de sqldinamico vc pode usar o clientdataset tb..

e so habilitar a opção allowcommandtext com datasetprovider..

se clientdataset for so de consulta, desabilita a propriedade getmetadata da query q melhora a performance tb

abração


GOSTEI 0
Marco Salles

Marco Salles

21/11/2006

Acho que o problema é conceitual...

O clientDataSet armazena tudo na memória , isto faz com que a aplicacção seje responsável pelo cache dos dados... Todos os dados de uma consulta são trazidos para a memoria

Quando se abre uma query, é o BDE que coordena a busca dos dados, so que ele não coloca todos os dados de uma so vez...

Para entender esta diferença , vamos supor que voce tenha uma tabela com muitos registros e um botão que coloque a query no ultimo registro(método last) .. Abra a aplicaçãoe , imediatamente apos ser mostrado o primeiro registro, pare o servidor da aplicação e click no botão... Voce receberá uma exceção...

Outra coisa muito importante , o tempo que voce espera usando uma query com o BDE , para abrir uma aplicação desse tipo é muito menor que o tempo que voce espera para abrir uma aplicação usando o clientDataSet

Existem alem de outras tecnicas de meçlhorar a performance do ClientDatset , voce definir o numero de registros que se deseja trazer , em cada operação utilizando o clientedataset.. Esta também é uma boa opção


GOSTEI 0
Brunolspp

Brunolspp

21/11/2006

realmente o uso do CDS é mto abrangente e como o colega falow existem varios fatores que influenciam na performance

eu deixei varios exemplos praticos de tecnicas com codigo fonte do q usei em varios sistemas comerciais de alta performance, requisição e disponibilidade, td baseado em datasnap e 99¬ em BSS.

Tem bastante coisa la rpa ajudar

eis o link: http://cc.borland.com/Author.aspx?ID=795118

e no mais estou aki para o que precisar

;)

Abração


GOSTEI 0
Marcelo_mileris

Marcelo_mileris

21/11/2006

Não sei se vai ser válido eu postar os resultados porém ai estão:

- Base de dados Firebird com 65031 registros (Claro que ninguem (acho eu né :D) faria uma consulta trazendo toda essa quantidade de registros... porém somente assim consegui ver a diferença de tempo)

[b:0f910ec8da]Componentes:[/b:0f910ec8da]
IBDatabase -> TIBTransaction -> IBQuery - DataSetProvider -> ClientDataSet

Consulta com o SQL direto na IBQuery sendo aberta pelo ClientDataSet:
Tempo: 00:02:11 (Dois minutos e 11 segundos)

Consulta com o SQL direto no CommandText do ClientDataSet:
Tempo: 00:01:41 (1 minuto e 41 segundos)

---

Alterando as propriedades ProviderFlags dos Fields adicionados no ClientDataSet (exceto chave primária) para:
[b:0f910ec8da]pfInUpdate [/b:0f910ec8da]- True
[b:0f910ec8da]pfInWhere[/b:0f910ec8da] - False
[b:0f910ec8da]pfInKey[/b:0f910ec8da] - False
[b:0f910ec8da]pfHidden[/b:0f910ec8da] - False

Chave Primária:
[b:0f910ec8da]pfInUpdate [/b:0f910ec8da]- True
[b:0f910ec8da]pfInWhere[/b:0f910ec8da] - True
[b:0f910ec8da]pfInKey[/b:0f910ec8da] - True
[b:0f910ec8da]pfHidden[/b:0f910ec8da] - False

Alterando também o UpdateMode do DataSetProvider para [b:0f910ec8da]upWhereKeyOnly[/b:0f910ec8da]
Tempo: 00:01:37 (1 minuto e 37 segundos)


Levando em conta o tempo de retorno com cada uma das configurações... ficou claro que o ClientDataSet com algumas configurações fica quase duas vezes mais rápido.

Agora o porque que mudando aquelas ´flags´ ele fica mais rápido eu não sei... somente me falaram que assim ficaria mais rápido porém não souberam me explicar direito... se alguem souber


GOSTEI 0
Marco Salles

Marco Salles

21/11/2006

Agora o porque que mudando aquelas ´flags´ ele fica mais rápido eu não sei... somente me falaram que assim ficaria mais rápido porém não souberam me explicar direito... se alguem souber


eu não trabalho com os IB ,[b:6d7803019d] mas a explicação com certeza é a mesma encontrada , quando se trabalha com os componentes DbExpress[/b:6d7803019d]

Se no IB voce tiver a oportunidade de colocar um Componente que irá ´visualizar´ e detalhar como esta sendo processada o seu Sql , voce podera chegar a algumas conclusões .. [b:6d7803019d]No DbExpress esse componente se chama TSqlMonitor e explicação seria assim:[/b:6d7803019d]

Coloque por curiosidade um TSqlMonitor na sua aplicação (so por curiosidade) e [b:6d7803019d]veje[/b:6d7803019d] o log gerado pela consulta Sql... Voce vera que definidindo os flags , voce estara parametrizando a sua instrução Sql , que sera reolvida pelo DataSetProvider....


[b:6d7803019d]Em outra palavras voce trocara menos informação com o Servidor..[/b:6d7803019d]

Ao analizar o log gerado pelo SqlMonitor , voce podera observar como sua [b:6d7803019d]instrução Sql ´Gerada´ < que sera resolvida pelo DataSetProvider > conterá menos ´campos´[/b:6d7803019d] , tanto na clausula Update como na clausula Where e portanto sera processada muito mais rapidamente pelo servidor.



GOSTEI 0
Titanius

Titanius

21/11/2006

Não sei se vai ser válido eu postar os resultados ClientDataSet (exceto chave primária) para: [b:490fcc1d46]pfInUpdate [/b:490fcc1d46]- True [b:490fcc1d46]pfInWhere[/b:490fcc1d46] - False [b:490fcc1d46]pfInKey[/b:490fcc1d46] - False [b:490fcc1d46]pfHidden[/b:490fcc1d46] - False Chave Primária: [b:490fcc1d46]pfInUpdate [/b:490fcc1d46]- True [b:490fcc1d46]pfInWhere[/b:490fcc1d46] - True [b:490fcc1d46]pfInKey[/b:490fcc1d46] - True [b:490fcc1d46]pfHidden[/b:490fcc1d46] - False Alterando também o UpdateMode do DataSetProvider para [b:490fcc1d46]upWhereKeyOnly[/b:490fcc1d46] Agora o porque que mudando aquelas ´flags´ ele fica mais rápido eu não sei... somente me falaram que assim ficaria mais rápido porém não souberam me explicar direito... se alguem souber


Bem, isto é meio que óbvio, pois setando o DataSetProvider para upWhereKeyOnly, na hora que ele vai gerar o SQL ele gera levando em conta a chave primária, ou seja, o campo que você marcar como pfInKey.

O ideal é você marcar lá no ClientDataSet, como [b:490fcc1d46]pfInKey := True e pfInWhere := True[/b:490fcc1d46] todos os campos que fazem parte de sua [b:490fcc1d46]chave primária[/b:490fcc1d46], assim o retorno será muito mais rápido.

Espero ter sido claro..

[]s


GOSTEI 0
Brunolspp

Brunolspp

21/11/2006

eita galera afiada!!!!

:D


GOSTEI 0
Júlio Ferreira

Júlio Ferreira

21/11/2006

Meus amigos do fórum!

Esse esqueminha do pfInKey para a chave primária está realmente correto. Mas comigo ainda não está funcionando...
Minha situação é um pouco diferente, pois meu servidor disponibilizar o ProviderDataSet através de uma conexão via ADOConnection e realizando uma query através de um ADOQuery.

O lado do cliente está normal, com um TClientDataSet configurado com o ProviderFlags desse mesmo jeito discutido neste tópico. Mas ainda assim, não está funcionando.

Existe alguma dica diferente para a minha situação ou ela simplesmente não funciona...
GOSTEI 0
POSTAR