Zum Inhalt springen

[Delphi 6] Datenbankzugriff


Empfohlene Beiträge

Hallo,

weiß jetzt nicht ob ich es in Programmierung->Delphi oder Datenbanken ansprechen soll, da es aber um Delphi geht hoffe ich das ich hier richtig bin.

Sachverhalt:

Der User gibt einen SQL-Befehl ein der dann an die Oracle-Datenbankserver geschickt wird. Das Ergebniss soll mit Delphi verarbeitet werden.

Problem:

Ich lasse eine Anzeige mitlaufen, die mir anzeigt wie viele Datensätze von Delphi verarbeitet wurden. Die ersten 600 gehen ziemlich schnell, die darauffolgenden fahren immer in 25'er Schritten voran bis die 1229 Datensätze abgearbeitet wurden. Das dauert zwar nur 33 sekunden aber es ist durchausmöglich das es mehrere 100.000 Datensätze sind.

Frage:

Wieso sind die ersten 600 Datensätze ruckzuck bearbeitet und die folgenden laufen in langsamen 25er Schritten.

Kann man da was machen? Also irgendwelche Einstellungen zur Verbindung?

Bei Google hab ich nicht wirklich Rat gefunden.

Danke für eure Hilfe.

Link zu diesem Kommentar
Auf anderen Seiten teilen

welche schnittstelle zur oracle-datenbank wird denn verwendet?

der flaschenhals könnte schon dort sein (allenfalls der Prefetch Count, wenn ODBC verwendet wird; die besagten 25er zeilenschritte kommen mir bekannt vor), oder aber in der delph-anwendung, wenn sie die zurückgegeben datensätze verarbeitet.

s'Amstel

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ohne Quellcode kann ich zu deinem Problem nix Konkretes sagen.

Interessant wäre zuerst mal rauszufinden, wo dein Flaschenhals eigentlich liegt. Kommen die Daten aus der DB zu langsam, oder dauert die Verarbeitung in Delphi zu lange?

Was genau wird in deiner Anzeige dargestellt?

<edit>

War wohl jemand schneller. ;)

</edit>

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo,

danke für die Unterstützung.

Der Zugriff auf die Datenbank erfolgt über die DOA-Schnittstelle.

Hab mir TOracleSession und ein TOracleQuery Objekt erstellt bzw. erstellen lassen, von Delphi.


... // Programmstart

OracleSession1.LogonUsername := sql_user;

OracleSession1.LogonPassword := sql_pw;

OracleSession1.LogonDatabase := sql_Database;

OracleSession1.LogOn;

OracleQuery1.Session := OracleSession1;

...// Ein Paar andere Dinge die nichts mit Oracle zu tun haben

OracleQuery1.SQL.Clear();

OracleQuery1.SQL.Add(sSql_query);

OracleQuery1.Execute();

iSpalten := OracleQuery1.FieldCount();

while not OracleQuery1.Eof do

         begin

               sSatz := '';

               for iIndex := 0 to iSpalten-1 do

                  sSatz := sSatz + VarToStr(OracleQuery1.Field(iIndex)) + '#';

               Label2.Caption := 'Verarbeitete Sätze -> ' +                            

                                                IntToStr(OracleQuery1.RowsProcessed);

               OracleQuery1.Next;

               // die Variable sSatz wird in eine Datei geschrieben mit write

         end;

// Ende der SQL-Verarbeitung

So ich hab jetzt mal mit einer ungenaueren Abfrage die Datenbank genervt :D.

Beim Ergebnis kamen dann ca. 581.000 Datensätze raus dauerte ca. 6 min.

Da hat er komischerweiße nicht bei 600 angehalten und in 25er Schritten weitergearbeitet, bei dieser Abfrage war es nur zufällig mittendrin.

Das sehe ich wenn mein Label2 nicht mehr hochzählt :D

Das sich die Anzeige auf die Performance auswirkt ist mir klar, nur ein ungeduldiger User macht das Programm hardcore zu (STRG+ALT+ENTF) :(.

So sehen die User wenigstens noch das das Programm etwas tut.

Hoffe der Code und die neuen Ereignisse helfen weiter :)

P.S gibt es eine möglichkeit herauszufinden wie viele Datensätze der SQL-Befehl liefern wird? Das ich meine Anzeige verbessern kann, also: Verarbeiteter Datensatz 403 von 1239?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Das mit den Threads würd ich mir dann halt mal anschauen, kann ja nicht so kompliziert sein ;)

Hilft mir das denn weiter wenn ich die Anzeige in einem anderen Thread laufen lasse? Ich hab ja nur eine CPU die schon zu 100% ausgelastet ist, wenn mein Programm läuft.

Wäre es schneller wenn ich die Daten erst in ein Grid einlese und dann in die Datei?? Ich würd ungern nochmal alles umschreiben :( ohne zu wissen das es _merklich_ etwas bringt.

Link zu diesem Kommentar
Auf anderen Seiten teilen

also soviel ich weiss greift DOA ja direkt (nona, steht ja D für direkt :D ) auf den oracle client zu - d.h. optimierungen könntest du höchstens noch dort rausholen. mehr wüsste ich an deinem code auch nicht besser zu machen, zumal du essentielle statusinfos ja schon aus objektvariablen wie RowsProcessed herausholst :)

gibt es eine möglichkeit herauszufinden wie viele Datensätze der SQL-Befehl liefern wird? Das ich meine Anzeige verbessern kann, also: Verarbeiteter Datensatz 403 von 1239?


VAR 

anzahlDS :Integer;

sSql_query := 'SELECT COUNT(*) FROM tabelle';

OracleQuery1.SQL.Clear();

OracleQuery1.SQL.Add(sSql_query);

anzahlDS := OracleQuery1.Field(0);

oder auch
OracleQuery1.Execute();

OracleQuery1.Last;

und allenfalls auch einen zähler mitlaufen lassen. ich weiss aber nicht, ob DOA (?) .Last oder MoveLast unterstützt.

s'Amstel

Link zu diesem Kommentar
Auf anderen Seiten teilen

...

Hilft mir das denn weiter wenn ich die Anzeige in einem anderen Thread laufen lasse? Ich hab ja nur eine CPU die schon zu 100% ausgelastet ist, wenn mein Programm läuft.

Wäre es schneller wenn ich die Daten erst in ein Grid einlese und dann in die Datei?? Ich würd ungern nochmal alles umschreiben :( ohne zu wissen das es _merklich_ etwas bringt.

Ist es überhaupt die Anzeige, die die Performance bremst? Läuft das Programm ohne die Zeile schneller?

Das mit dem Grid würde überhaupt nix bringen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Also ich hab jetzt mal getestet

ca. 581.000 Datensätze

mit Ausgabe und Application.ProcessMessage -> Dauer 6:15 Minuten

ohne Ausgabe und Application.ProcessMessage -> Dauer 5:45 Minuten

Wenn ich mich nicht verrechnet habe dann :D sind da 30 Sekunden unterschied, bei diesem Zeitaufwand sind dann 30 Sekunden auch nicht die Welt.

Vorallem weil der Psychische Effekt wegfällt. 30 Sekunden ohne Textanzeige dauern viel länger als mit :P.

@Amstelchen

Wie du oben geschrieben hast steht DOA für Direct Oracle Access, jetzt hab ich eben gedacht ich könnte noch etwas, eben weil es direkt ist, rausschlagen.

Die Lösung mit dem weiteren SQL, ist zwar ganz in Ordnung nur dauert das Senden und abwarten des SQL's sowie das Durchlaufen fast genauso lang wie wenn ich es gleich verarbeite.

Das Verwenden von First, Last und MoveTo muss ich noch ausprobieren.

>> EDIT 1:

Generell kann man es verwenden, in der Hilfe steht dazu folgendes

This feature does not yet work properly on Oracle 9.0 and 9.2 due to Oracle Bugs 2286367 and 2478181, which may cause ORA-00600 exceptions.

Wir nutzen Oracle8i sprich ich kann sie nicht verwenden :(

Oder hab ich da was falsch interprediert?

<< EDIT 1:

@grueni: wegen den Thread's: die helfen mir nicht weiter oder seh ich das falsch?

Link zu diesem Kommentar
Auf anderen Seiten teilen

...

@grueni: wegen den Thread's: die helfen mir nicht weiter oder seh ich das falsch?

Kommt drauf an. Du läßt in jedem Schleifendurchlauf die Windowsnachrichtenschleife abarbeiten. Wenn du die Datenbankoperation vom VCL-Thread trennst, mußt du das nicht bei jedem Durchlauf machen.

Ich nehme mal an, das "ProcessMessages" hast du eingebaut, damit deine Anwendung nicht "steht", das kannst du dir bei zwei verschiedenen Threads sparen.

P.S.: Ich würde zusätzlich noch den Mauszeiger als Sanduhr darstellen, solange das Programm "rattert". ;)

Link zu diesem Kommentar
Auf anderen Seiten teilen

@grueni: Stimmt, das Application.ProcessMessages hab ich eingebaut damit der User nicht das gefühl bekommt die Anwendung wäre abgestorben ;D.

Das mit dem Mauszeiger is ne gute Idee, werd ich gleich übernehmen.. :)

Ich werd mich dann gleich noch in die Thread-Theorie einlesen.

1) hoffe ich finde was in der Hilfe oder bei google.

2) hoffe das es nicht allzuschwer wird...

hab mir noch folgendes Überlegt:

- kann ich die performance verbessern wenn ich weniger spalten als ergebnis erwarte? bis jetzt hab ich select * from ...

- kann man den SQL sonstwie optimieren?

- die tabelle hat ein paar millionen einträge, wie kann ich nachschauen welche felder mit einem index belegt sind? (pl/sql developer)

muss mich bezüglich der obigen überlegungen noch informieren ;)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ein Tutorial über Multithreading wirst bestimmt finden, da gibts ne ganze Menge.

Als Behelfslösung würde ich vorschlagen, laß deine Anzeige nur z.B. bei jedem 10. Schleifendurchlauf aktualisieren. Das müßte schon ein bißchen was bringen.

...und denk wegem dem Mauszeiger dran, den im finally wieder zurückzusetzen, sonst bleibt das nämlich ne Sanduhr, wenn dein Programm in der Schleife abschmiert.

Link zu diesem Kommentar
Auf anderen Seiten teilen

@grueni: danke wegen des tipps, nur irgendwie öndert der sich von selber dauernd. Also einmal ist er crArrow und dann wieder crHourGlass, dann wieder anders herum. Dabei hab ich gleich an Anfang gesagt Form1.Cursor := crHourClass und am ende der Prozedur crArrow... noch keine Ahnung was das ist.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo mitnander,

hab jetzt nen Thread der die Arbeit des Auswertens der Tabelle sowie die Dateibehandlung in die Hand nimmt. Die Verarbeitungszeit dauert immernoch

genauso kurz oder lang ;) Das einzige was besser ist ist das das Fenster nicht mehr über Application.ProcessMessages aktualisiert werden muss.

Link zu diesem Kommentar
Auf anderen Seiten teilen


...

               OracleQuery1.Next;

               // die Variable sSatz wird in eine Datei geschrieben mit write

         end;

// Ende der SQL-Verarbeitung

So ich hab jetzt mal mit einer ungenaueren Abfrage die Datenbank genervt :D.

Beim Ergebnis kamen dann ca. 581.000 Datensätze raus dauerte ca. 6 min.

Da hat er komischerweiße nicht bei 600 angehalten und in 25er Schritten weitergearbeitet, bei dieser Abfrage war es nur zufällig mittendrin.

Das sehe ich wenn mein Label2 nicht mehr hochzählt :D

Hast du mal probiert, das Schreiben in die Datei auszukommentieren? Wenn eine Datei eine gewisse Größe erreicht (weiss ja nicht, wie deine Satzlänge ist), kann so ein Schreibzugriff ziemlich bremsen.

Kommentier den mal aus und lass es durchlaufen.

Außerdem, was benutzt du für die Dateibehandlung? Write deutet für mich nicht auf einen TFileStream hin, oder? Ein TFileStream ist der alten TFile-Methode auf jeden Fall vorzuziehen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Guten Morgen,

so läuft mein Dateizugriff:


var tf           : TextFile; // Handle für eine Textdatei //

begin

      ...

      AssignFile(tf, sFilename);

      {$i-}

      Rewrite(tf);

      {$i+}

      ...

      // Fehlerbehandlung des IOResults //

      ...

      // Schleife zur Verarbeitung des SQL-Results //

      ...

      Writeln(tf, sSatz);

      // Ende der Schleife //

      ...

      CloseFile(tf);

      ...

end;

Ich hab den WriteLn mal kommentiert, es hat genauso lang gedauert.

Bei einer Ergebnismenge von 1300 Datensätzen fängt er bei 600 wieder mit 25 Schritten an. Es muss also irgendwas anderes passieren z.B. das die Datenbank die Daten nicht liefert, was auch die sporadische Datenversorgung bei 581.000 Datensätzen erklären würde. Der Grund ist mir nur nicht bekannt.

Ich glaub zu wissen das es nicht am Dateizugriff liegt, bin mir aber nicht sicher, gehe nur deshalb davon aus weil die Verarbeitung ohne Dateizugriff genauslang dauert.

Die Satzlänge beträgt: 712 Bytes

In der Datei stehen aber 782 Bytes = 712 Bytes (Nutzbytes) + 2 Steuerbytes (CR/LF) + 68 Trennbytes (Trennzeichen der Spalten)

Sprich das Programm schreibt pro Datensatz 782 Bytes in die Datei.

Die Anzahl der Spalten kann noch variieren, dies kann ich allerdings erst machen wenn mir jemand (z.B. Auftragssgeber) sagt welche er benötigt.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich hab mal ein kleines Programm gemacht zum Testen. Hab aber kein Oracle hier und hab MySQL genutzt. Zugriff über dbExpress und mit Delphi7. dbExpress wurde ja aber mit D6 eingeführt. Als Treiber haben wir den dbExpress Treiber von Core Lab (http://crlab.com/dbx/ - geht auch für Oracle).

Meine Tabelle sieht so aus:


DROP TABLE IF EXISTS `test`.`IOTest`;

CREATE TABLE  `test`.`IOTest` (

  `id` int(10) unsigned NOT NULL auto_increment,

  `Data1` char(255) collate latin1_german1_ci NOT NULL default '',

  `Data2` char(255) collate latin1_german1_ci NOT NULL default '',

  `Data3` char(255) collate latin1_german1_ci NOT NULL default '',

  PRIMARY KEY  (`id`)

) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_german1_ci;

Also ungefähr die Satzlänge, die du auch hast. Die hab ich gefüllt mit Daten, zuerst mal mit 1500 Sätzen. Danach hab ich alle gelesen (SELECT * ...) und in eine Textdatei geschreiben. Das ganze dauerte vielleicht ne Sekunde. Dann auf 15000 Sätze erhöht, da hat das Schreiben der Sätze schon was länger gedauert, also schreiben in die DB. Dann wie eben alles gelesen und als Text gespeichert... 2-3 Sekunden (geschätzt). Hier mal mein Programm:

unit MainUNT;


interface


uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, DB, SqlExpr, StdCtrls, ExtCtrls, ActnList, XPStyleActnCtrls,

  ActnMan, ComCtrls;


type

  TForm1 = class(TForm)

    SQLConnection: TSQLConnection;

    qryMain: TSQLDataSet;

    amMain: TActionManager;

    aiFill: TAction;

    aiProcess: TAction;

    pnlTop: TPanel;

    btnFill: TButton;

    pnlMain: TPanel;

    btnProcess: TButton;

    sbMain: TStatusBar;

    procedure aiFillExecute(Sender: TObject);

    procedure aiProcessExecute(Sender: TObject);

  private

    { Private-Deklarationen }

  public

    { Public-Deklarationen }

  end;


const

  cSQL_FILL = 'INSERT INTO IOTest (id, Data1, Data2, Data3) VALUES (NULL, %s, %s, %s)';

  cSQL_PROCESS = 'SELECT * FROM IOTest';


  cSQL_Empty = 'DELETE FROM IOTest';


var

  Form1: TForm1;


implementation


{$R *.dfm}


//******************************************************************************

//*** TForm1.aiFillExecute

//***

//*** Tabelle Füllen

//******************************************************************************

procedure TForm1.aiFillExecute(Sender: TObject);

type

  TData = array[0..254] of Char;

var Str1, Str2, Str3: TData;

  saveCursor: TCursor;

    I, n: Integer;

begin

  saveCursor := Screen.Cursor;

  Screen.Cursor := crHourGlass;

  try

    //*** zuerst leeren

    qryMain.CommandText:= cSQL_Empty;

    qryMain.ExecSQL;

    //*** wieder füllen

    n:= 65;

    for I := 1 to 15000 do    // Iterate

    begin

      //*** Daten vorbereiten

      FillChar(Str1, 255, chr(n));

      FillChar(Str2, 255, chr(n));

      FillChar(Str3, 255, chr(n));

      Inc(n);

      if n> 90 then

        n:= 65;


      qryMain.CommandText:= Format(cSQL_FILL, [QuotedStr(Str1), QuotedStr(Str2), QuotedStr(Str3)]);

      qryMain.ExecSQL;

    end;    // for

  finally

  	Screen.Cursor := saveCursor;

  end;  // try/finally

end;


//******************************************************************************

//*** TForm1.aiProcessExecute

//***

//*** Daten lesen und schreiben

//******************************************************************************

procedure TForm1.aiProcessExecute(Sender: TObject);

const cFilename = 'Data.txt';

var aList: TStringList;

  saveCursor: TCursor;

  I: Integer;

    aFileName, temp: String;

begin

  saveCursor := Screen.Cursor;

  Screen.Cursor := crHourGlass;

  try

    //*** Datei vorbereiten

    aFileName := ExtractFilePath(Application.ExeName)+cFileName ;

    aList:= TStringList.create;

    try

      //*** Daten lesen

      qryMain.CommandText:= cSQL_PROCESS;

      qryMain.Open;

      while not qryMain.EOF do

      begin

        for I := 0 to qryMain.Fields.Count  - 1 do    // Iterate

        begin

          aList.Add(qryMain.Fields[i].asString);

        end;    // for

        qryMain.next;

      end;    // while

      aList.SaveToFile(aFileName);

    finally

    	FreeAndNil(aList);

    end;  // try/finally

  finally

  	Screen.Cursor := saveCursor;

  end;  // try/finally

end;


end.

Das Formular selber enthält nur eine TSQLConnection und ein TSQLDataSet zum Zugriff auf die DB. Dann 2 Panels (einfach so...) und 2 Buttons und einen ActionManager. Im Action Manager sind 2 Aktionen definiert und die je einem Button zugeordnet.

An Delphi kann es also nicht liegen, an Windows (schreiben der Daten) auch nicht. (Ach ja, ich benutze eine TStringList zum Speichern...also erstmal alles in den Speicher, dann am Ende auf die Platte, bei 15000 Sätzen ung. 11MB Datei).

Ich schätze mal, es liegt entweder an den Oracle einstellungen bei euch, oder am DB Zugriff (also an DOA). Vielleicht frägst du mal den DB-Admin, kann ja sein, dass die DB für solche Zugriffe bissel angepasst werden muss o.ä. (bzw. dein Treiber).

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo,

danke erstmal für die viel Mühe die du dir gemacht hast.

Was ich auf den ersten blick gesehen hab verwendest du das TSQLDataSet ich verwende TOracleQuery.

Evlt. liegt ja da schon der große Unterschied. Sicher weiß ich es noch nicht. Ich schreib nochmal ob es merklich schneller geworden ist wenn ich es ausprobiert habe.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo,

hab jetzt mit deinem Quellcode gearbeitet, leider muss ich dir mitteilen das es so auch nicht schneller geht. Zumindest bei mir.

Ich darf die Treiber nicht verändern, ich sitze an einer End-User-Maschine auf welchen mein Programm später laufen soll.

Mit einem DB-Admin muss ich noch reden.

Was soll ich denn an den DOA-Einstellungen anpassen? Hab da nichts gefunden was mir helfen könnte.

Was mir während der Programmierungsarbeit noch eingefallen ist, warum bei dir die Auswertung schneller abläuft

- Du hast die Datenbank bei dir lokal

- Es greifen keine anderen User auf deine Datenbank zu

Ich werd jetzt einfach mal das Programm so lassen wie es ist, auch wenn es mir persönlich noch zu langsam geht, aber evlt. ist der Auftragsgeber schon zufrieden.

Wer allerdings noch gute Ideen hat -> nur her damit <- ich werds ausprobieren. Dann gibt es halt die Version 1.01 :bimei

Link zu diesem Kommentar
Auf anderen Seiten teilen

- Du hast die Datenbank bei dir lokal

- Es greifen keine anderen User auf deine Datenbank zu

1. Nein.

2. Ja.

Aber der Oracle DB-Server wird wohl auch um einiges besser ausgestatet sein als unser Testserver (mehrere VMs auf einem Rechner, VM läuft unter Debian mit Apache und MySQL und mit 128 MB Speicher)

Auch wenn ich das auf unserem "echten" DB-Server testen würde, denk ich nicht, dass der Unterschied so groß wäre ;)

Was du an DOA ändern könntest... das solltest du ja deinen DB-Admin fragen. Ich geh einfach mal davon aus, der kennt sich mit Oracle und den Treibern aus und kennt vielleicht den ein oder anderen Kniff.

Scheinbar ist das ja nur bei großen Ergebnismengen so. Also entweder durch die Anzahl sätze oder die Satzlängen. Was du mal machen könntest wäre, eine Testtabelle mit z.B. 1 oder 2 Feldern und es mal damit probieren.

Ansonsten gibt es bei der DOA-Komponente vielleicht ne eigenschaft, ob sofort alle Daten geholt werden sollen, oder immer nur stückweise. Beim ClientDataSet z.B. über PacketRecords.

Danach hört sich das Verhalten zwar nicht direkt an, aber vielleicht mal als anstoß, etwas in der Art zu suchen.

Hast du mal probiert, alle Sätze nur anzeigen zu lassen? In einem Grid oder so. BRaucht er da genauso lang?

Wie sieht es denn mit anderen Anwendungen aus, die auf die DB zugreifen und auch viele Sätze zurückliefern? Und wenn die Anzeige genausolang braucht, hast du ein anderes Tool, mit dem du das mal gegentesten könntest (z.B. der Delphi SQL-Explorer oder auch eins direkt von Oracle oder so)?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Nachtrag: Hat etwas gedauert, aber ich hab es grad mal auf unserer produktiv DB getestet (DB2\400). Das Eintragen der 15000 Sätze dauert natürlich was, ob aber wirklich länger weiß ich nich so genau. Das Lesen und Schreiben dauerte knapp 4 Sekunden (Button gedrückt und langsam gezählt).

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo,

so hab jetzt die Ursache aber nicht die Lösung :)

Hab mal meine Zusammengebaute abfrage im PL/SQL-Developer ausgeführt und mir alle Ergebnisse anzeigen lassen. Da musste ich feststellen das der PL/SQL-Developer auch bis 600 Datensätze ruckzuck und ab da in 'Stücken' und die Verarbeitung von 1301 Datensätzen 34 Sekunden, genausolang braucht meine Anwendung um die Daten zu verarbeiten.

Sprich mein Programm arbeitet ganz in Ordnung, da kann ich nichts mehr besser machen. Muss mal einen DB-Admin suchen und fragen, evlt. gibt es einstellungen die man noch machen kann, wie du schon sagtest JesterDay.

Melde mich wenn ich was neues in Erfahrung gebracht habe.

Ich bin nur leider jetzt 1 Woche nicht in der Arbeit, was heisst wenn ich es heut nicht mehr schaffe dauert es ein wenig bis ich mich wieder melde.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...