Amélioration performance bases Paradox

Signaler
Messages postés
49
Date d'inscription
jeudi 4 septembre 2008
Statut
Membre
Dernière intervention
31 janvier 2010
-
Messages postés
49
Date d'inscription
jeudi 4 septembre 2008
Statut
Membre
Dernière intervention
31 janvier 2010
-
Bonjour à tous,

Je travaille actuellement sur un logiciel multimédia et j'ai besoin de parcourir l'ensemble d'un répertoire (sous répertoires et fichiers) pour stocker la liste dans une base de type Paradox.

J'ai donc mis au point un algo récursif qui parcours l'arborescence (parcours 250 éléments en 100ms) et extrait la date, heure de modification et la taille des fichiers.

Pour stocker tout ça j'utilise un objet TTable ouvert en mettant le chemin de la table dans tableName et Active:= True.

Voici mon code d'ajout des données :

TABLE_info.indexFieldNames:='Key';
TABLE_info.append;
TABLE_info.fields[0].value:=newKey;
TABLE_info.fields[1].value:=parcours;
TABLE_info.fields[2].value:=ENREGISTREMENT_DE_TYPE_REPERTOIRE;
TABLE_info.fields[3].value:=0; // taille du repertoire
TABLE_info.fields[4].value:=dateDerniereMAJ;
TABLE_info.fields[5].value:=heureDerniereMAJ;
TABLE_info.post;

A la fin je fait un active := False et un Free.

Mon problème c'est que quand je met ces 9 lignes le temps passe de 100ms à 169 000 ms !!!

Mon algo est récursif dans le sens ou la fonction se rappelle lorsqu'elle tombe sur un répertoire afin d'en traiter le sous arbre. J'ai testé la fonction et elle parcours bien l'ensemble de l'arbre (à l'aide de findfirst) et ce une seule fois.

J'ai donc pensé que l'ouverture en parallèle des tables causé par la récursivité pausait problème. J'ai donc essayé d'ouvrir et de fermer à chaque itération (approx 169 000 ms aussi).

J'ai également testé ADO mais je ne suis pas parvenu à la faire fonctionné correctement.

Je fait donc appel à vous, pour me donner des pistes sur des méthodes d'insertion en base de données paradox plus performantes.

Si vous constatez quelque chose d'étrange dans mon raisonnement n'hésitez pas à me demander.

Merci d'avance pour votre réponses.

Ludovic

24 réponses

Messages postés
4719
Date d'inscription
dimanche 26 février 2006
Statut
Modérateur
Dernière intervention
1 février 2021
14
Bonjour,
il faudrait connaître exactement quel est le code qui prend du temps..
il faut faire des pointages plus précis.

cantador
Messages postés
49
Date d'inscription
jeudi 4 septembre 2008
Statut
Membre
Dernière intervention
31 janvier 2010

Bonjour,

Merci pour votre réponse.

Les lignes de code qui prennent du temps sont les 9 que j'ai mises dans mon post.

Si elle sont présentes il faut 169 000 ms et si elles sont commentées il faut 100 ms.

Voulez-vous dire, laquelle parmi les 9 ?

Cordialement

Ludovic
Messages postés
4719
Date d'inscription
dimanche 26 février 2006
Statut
Modérateur
Dernière intervention
1 février 2021
14
oui bien sûr

cantador
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
14
Salut,

Tu dois pouvoir faire des lots j'imagine. Connais pas TTable, mais peut être qu'en faisant X append avant de faire un post, ça irait mieux.
Messages postés
49
Date d'inscription
jeudi 4 septembre 2008
Statut
Membre
Dernière intervention
31 janvier 2010

Bonjour,

Merci pour vos réponses.

J'ai fait d'autres tests.

- avec insert (fait le post automatiquement) : plus rapide (118 000 ms)
- avec append puis post : (169 000 ms)
- AppendRecord(tableau) : (170 000 ms)
- InserRecord(tableau) : (170 000 ms)

Ce que je ne comprend pas c'est le fait qu'InsertRecord soit moins performant qu'un Insert fait à la main.

J'ai essayé de faire des append non suivi d'un post et de faire le post à la fin mais il me dit que la table n'est pas dans un état permettant post.

Je continue les tests.

Si vous avez d'autres idées pour ajouter des d'enregistrement dans une table paradox.
(mon algo est récursif)

Cordialement

Ludovic
Messages postés
4719
Date d'inscription
dimanche 26 février 2006
Statut
Modérateur
Dernière intervention
1 février 2021
14
oui, mais tu n'as toujours pas répondu à la question :

TABLE_info.indexFieldNames:='Key';
TABLE_info.append;
TABLE_info.fields[0].value:=newKey;
TABLE_info.fields[1].value:=parcours;
TABLE_info.fields[2].value:=ENREGISTREMENT_DE_TYPE_REPERTOIRE;
TABLE_info.fields[3].value:=0; // taille du repertoire
TABLE_info.fields[4].value:=dateDerniereMAJ;
TABLE_info.fields[5].value:=heureDerniereMAJ;
TABLE_info.post;

quelle est la ligne qui prend du temps ?

cantador
Messages postés
49
Date d'inscription
jeudi 4 septembre 2008
Statut
Membre
Dernière intervention
31 janvier 2010

Je ne suis pas parvenu à le calculer, avec GetTickCount il me renvoie 0 si je calcule le temps entre chaque ligne.

Avez-vous une autre méthode de calcul du temps ?

En faisant insert à la place de append et post je gagne pas mal de temps.

Je pense donc que c'est la méthode d'ajout (insert ou append) qui prend le plus de temps. Je suis d'accord qu'il faudrait que je parvienne à le vérifier.

Merci d'avance pour votre réponse.

Ludovic
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
14
Une classe de chronométrage, codée à l'arrache :

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Déclarations privées }
  public
    { Déclarations publiques }
  end;

type TPerformanceCounter = class
  public
    constructor Create;
    procedure Start;
    function Stop: Int64;
  private
    _nFrequency: Int64;
    _nBegin: Int64;
end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

constructor TPerformanceCounter.Create;
begin
  inherited;
  QueryPerformanceFrequency(_nFrequency);
end;

procedure TPerformanceCounter.Start;
begin
  QueryPerformanceCounter(_nBegin);
end;

function TPerformanceCounter.Stop: Int64;
var
  nEnd: Int64;
begin
  QueryPerformanceCounter(nEnd);
  Result:= ((nEnd - _nBegin) * 1000000) div _nFrequency;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  counter: TPerformanceCounter;
begin
  counter:= TPerformanceCounter.Create;

  counter.Start;
  Sleep(2);
  ShowMessage(IntToStr(counter.Stop) + ' microsecondes');
  counter.Start;
  Sleep(10);
  ShowMessage(IntToStr(counter.Stop) + ' microsecondes');

  FreeAndNil(counter);
end;

end.
Messages postés
4719
Date d'inscription
dimanche 26 février 2006
Statut
Modérateur
Dernière intervention
1 février 2021
14
bien obligé de faire un post derrière
un append pour chaque enregistrement..

un append peut prendre du temps si par exemple la table est volumineuse..

118 000 ms, ce qui fait environ 2minutes..
ça fait beaucoup je trouve...

il doit y avoir un truc quelque part je pense...

combien y a t-il d'enregistrements au maximum ?

cantador
Messages postés
49
Date d'inscription
jeudi 4 septembre 2008
Statut
Membre
Dernière intervention
31 janvier 2010

Merci pour vos réponses.

Pour le temps je testerais avec la classe que vous m'avez donné.

Au début je pars avec une table vide et je la rempli avec 250 enregistrements environ.

Visiblement un insert est plus performant qu'un append / post (il ne met pas les enregistrement dans le même ordre, non ?)

Je viens de regarder dans l'administrateur bde et j'ai tenté d'améliorer les paramètres de ram, nombre d'handle... C'est très légèrement mieux.

Par contre dans Administrateur BDE -> Pilotes -> Natif -> Paradox j'ai version 4.0 !
Savez-vous comment mettre à jour vers la 7.0 ? (je n'ai pas trouvé sur google)

Je suis étonné qu'il n'utilise pas une version plus récente car je suis sous Delphi 2009 (Win Xp).

Merci d'avance pour vos réponses.
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
14
Un post par append ?
Bah il doit y avoir un autre moyen de faire des lots alors.

Peut être avec TBatchMove ?
Messages postés
4719
Date d'inscription
dimanche 26 février 2006
Statut
Modérateur
Dernière intervention
1 février 2021
14
avec 250 enregistrements environ.

c'est tout petit petit.
il y a donc bien un truc.
la version 7 va améliorer c'est sûr
(il faut la choisir au moment de créer la table)
mais pas diviser les temps par 2..

pour aviter append et post, il faut utiliser :
appendrecord();

mais je suis persuadé que la boucle de recherche des fichiers doit prendre du temps...

cantador
Messages postés
4719
Date d'inscription
dimanche 26 février 2006
Statut
Modérateur
Dernière intervention
1 février 2021
14
et je ferai d'abord la recherche en plaçant les données dans un tableau dynamique puis je stockerai à la fin tout le tableau dans la table.

je boucle sur le tableau de 0 à n - 1 et je stocke :
var
tabR : array of string;
i:integer;
begin
setlength(tabR,Maxnbffich);
for i:= 0 to high(tabR) do
begin
MaTable.Append;
Matable.Chp1.Value := tabR[i];
--
--
MaTable.Post;
end;
end;


cantador
Messages postés
4719
Date d'inscription
dimanche 26 février 2006
Statut
Modérateur
Dernière intervention
1 février 2021
14
setlength(tabR,Maxnbffich);

>> opérations de recherche de fichiers<<<


for i:= 0 to high(tabR) do




cantador
Messages postés
49
Date d'inscription
jeudi 4 septembre 2008
Statut
Membre
Dernière intervention
31 janvier 2010

Bonjour,

Merci pour vos réponses.

J'avais essayé le tableau dynamique mais j'ai bloqué sur une chose. Ma fonction étant récursive elle doit renvoyer le tableau des résultats pour le sous-arbre. Ce paramètre doit être optionnel pour ne pas changer tout les appels dans l'application.

Je ne suis pas parvenu à passer en paramètre un tableau dynamique (5*x) optionnel. Le compilateur me demandait une valeur par défaut et lorsque j'en donnais une il me disait qu'il n'en fallait pas (ou mauvais type ?).

Il reste aussi le problème de la concaténation de tableaux multi-colonnes.

Si vous avez des pistes pour les deux problèmes ;)

Merci d'avance et bonne matinée

Ludovic
Messages postés
49
Date d'inscription
jeudi 4 septembre 2008
Statut
Membre
Dernière intervention
31 janvier 2010

re

J'oubliais, je n'ai pas trouvé la mise à jour vers Paradox 7.

Vous avez une idée ?

Merci ;)
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
14
Je ne suis pas parvenu à passer en paramètre un tableau dynamique (5*x) optionnel. Le compilateur me demandait une valeur par défaut et lorsque j'en donnais une il me disait qu'il n'en fallait pas (ou mauvais type ?).

Bah tu as un paquet de façon de t'en sortir, par exemple avec une surcharge :
procedure DisplayArray(lpArray: Array of String); overload;
var
  nI: Integer;
  lpStr: String;
begin
  lpStr:= '';
  for nI:= 0 to High(lpArray) do
    lpStr:= lpStr + lpArray[nI];
  ShowMessage(lpStr);
end;

procedure DisplayArray(); overload;
begin
  DisplayArray([]);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  lpArray: Array of String;
begin
  SetLength(lpArray, 2);
  lpArray[0]:= 'toto';
  lpArray[1]:= 'titi';
  DisplayArray(lpArray);
  DisplayArray();
  lpArray:= nil;
end;


Il reste aussi le problème de la concaténation de tableaux multi-colonnes.

Est ce vraiment un problème ?
procedure TForm1.Button1Click(Sender: TObject);
var
  lpArray1: Array of Array of String;
  lpArray2: Array of Array of String;
  nArray1Len: Integer;
  lpResult: String;
  nI: Integer;
begin
  SetLength(lpArray1, 2);
  SetLength(lpArray1[0], 2);
  SetLength(lpArray1[1], 2);
  lpArray1[0, 0]:= '1';
  lpArray1[0, 1]:= 'a';
  lpArray1[1, 0]:= '2';
  lpArray1[1, 1]:= 'b';

  SetLength(lpArray2, 2);
  SetLength(lpArray2[0], 2);
  SetLength(lpArray2[1], 2);
  lpArray2[0, 0]:= '3';
  lpArray2[0, 1]:= 'c';
  lpArray2[1, 0]:= '4';
  lpArray2[1, 1]:= 'd';

  // Concaténation
  nArray1Len:= Length(lpArray1);
  SetLength(lpArray1, nArray1Len + Length(lpArray2));
  for nI:= 0 to High(lpArray2) do
  begin
    SetLength(lpArray1[nArray1Len + nI], 2);
    lpArray1[nArray1Len + nI][0]:= lpArray2[nI][0];
    lpArray1[nArray1Len + nI][1]:= lpArray2[nI][1];
  end;

  // Affichage
  for nI:= 0 to High(lpArray1) do
  begin
    lpResult:= lpResult + lpArray1[nI][0];
    lpResult:lpResult + ' ';
    lpResult:= lpResult + lpArray1[nI][1];
    lpResult:= lpResult + sLineBreak;
  end;
  ShowMessage(lpResult);

  // Libération
  for nI:= 0 to High(lpArray1) do
  begin
    lpArray1[nI]:= nil;
  end;
  lpArray1:= nil;

  for nI:= 0 to High(lpArray2) do
  begin
    lpArray2[nI]:= nil;
  end;
  lpArray2:= nil;
end;
Messages postés
49
Date d'inscription
jeudi 4 septembre 2008
Statut
Membre
Dernière intervention
31 janvier 2010

Merci beaucoup pour ta réponse.

Je teste tout ca.

Bon app ;)
Messages postés
49
Date d'inscription
jeudi 4 septembre 2008
Statut
Membre
Dernière intervention
31 janvier 2010

J'ai essayé de mettre sous forme de fonction :

procedure concat(source,dest:Array of String);
var
nArray1Len,nI,nJ:integer;

begin
nArray1Len:= Length(source);

SetLength(source, nArray1Len + Length(dest));

for nI:= Low(dest) to High(dest) do
begin

SetLength(source[nArray1Len + nI], Length(source[Low(source)]));

for nJ:= Low(source[nI]) to High(source[nI]) do
begin
source[nArray1Len + nI][nJ]:= dest[nI][nJ];
end;
end;
end;

Le setLength ne compile pas en disant : Types incompatibles.
Si je remplace source par un Array of String créé dans Var ca compile mais il bloque sur Low / High en disant que ces fonctions ne peuvent être appelés sur une chaine longue.

Quelle est la différence entre un tableau en paramètre et un tableau créé dans Var ?

Que dois-je faire ?

Merci d'avance pour vos réponses.

Ludovic
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
14
Houlà. Pas compris ton code moi.

source,dest:Array of String

C'est des tableaux à une dimension, alors que les miens sont à deux dimension vu que tu avais dit "tableaux multi-colonnes".