Anzahl Datensätze



  • Frage, wo steht dann meine Anzahl drin? Ich hab das jetzt mal so angefangen.

    CDatabase m_db;
    	m_db.Open( _T( "ACR" ), FALSE,true, _T( "ODBC;UID=anyusr;PWD=anyusr" ),false);
    	m_db.ExecuteSQL("Select count(*) from [dbo].[TRWErgebnisse]");
    

    Wo steht jetzt mein Ergebnis von count?

    (zur Zeit: ich sollte für count halt unter ca 2Sekunden bleiben)



  • Gib der Spalte doch ne richtige Bezeichnung:

    select count(*) as anzahl from [tabelle]
    

    dann hast du im ersten Record des Recordset die Anzahl..

    open
    

    nicht

    ExecuteSQL
    


  • geht sowas denn nicht ohne zusätzliche Spalte? Ich hab in der Tabell mittlerweile ca 160 Spalten und 5 virtuelle Spalten, also kalkulierte Felder. Ich will irgendwie drum rum kommen nochmal ne Spalte zu verwenden. Und wieso gleich beim open das SQL-State mitgeben? Warum nicht mit execute SQL?



  • Du sollst nicht eine neue Spalte oder gar Tabelle anlegen. 🙄

    So, wie das beschrieben wurde, wird eine Art "temporäre Tabelle" gemacht, wo genau eine Spalte drin ist (anzahl) und die nur eine Zeile hat.
    Diese "Tabelle" landet mit dem Open Befehl in dem Recordset und du hast die Anzahl. 🙂



  • Okay, das mit dem Open hab ich blöd geschrieben und das mit der Bezeichnung hast du nicht richtig verstanden 🙂

    CDatabase db;
            db.Open( _T( "ACR" ),FALSE,true,_T("ODBC;UID=anyusr;PWD=anyusr"),false);
    	CRecordset Set(&db);
    
    	CString strAnzahl;
    	CString strSQL = "Select count(*) as anzahl from [dbo].[TRWErgebnisse]";
    
    	Set.Open(CRecordset::dynaset | CRecordset::forwardOnly, strSQL);
            Set.MoveFirst()
    	if(!Set.IsEOF())
    	{
    	        Set.GetFieldValue("ANZAHL", strAnzahl);
    	}
    
    	Set.Close();
    
            // ungetestet getippt, könnten Fehler drin sein
    


  • aaahhhh OK.
    Jetzt hab ich das verstanden. Nur wenn ich den Source so probiere bekomme ich einen Fehler mit dem ich nichts anfangen kann

    ---------------------------
    ACRSQL
    ---------------------------
    Datensatzgruppe unterstützt nur Vorwärtsbewegung.
    ---------------------------
    OK
    ---------------------------

    Ob Debug oder Release ist egal! Was ist falsch? ~(Ansonsten TipTop, ohne Probieren! Nur ein Semikolon hat gefehlt nach move first.)~

    .



  • Las mal das MoveFirst weg, damit springt man zum ersten record, allerdings wird das RecordSet mit ForwardOnly geöffnet, da kann er natürlich nicht zurück springen 🙂 Emdweder das ForwardOnly wegnehmen, oder das MoveFirst(), dann sollte es klappen..



  • WOW! Jetzt geht es! Hab jetzt noch kleine Anpassungen gemacht, und es geht genau so wie ich es wollte.
    Jetzt hab ich es so:

    CDatabase db; 
        db.Open( _T( "ACR" ),FALSE,true,_T("ODBC;UID=anyusr;PWD=anyusr"),false); 
    
    	CRecordset Set(&db); 
    
        CString strAnzahl; 
        CString strSQL = "Select count(*) as ANZAHL from [dbo].[TRWErgebnisse] where " + m_sResult; 
    
        Set.Open(CRecordset::dynaset | CRecordset::forwardOnly, strSQL); 
        if(!Set.IsEOF()) 
        { 
    		Set.GetFieldValue("ANZAHL", strAnzahl);
    		m_sSuchen = strAnzahl;
        } 
    
        Set.Close(); 
    	UpdateData(false);
    

    Ich würde jetzt noch gerne die Zeit ermitteln, die benötigt würde, um diese Anzahl an datensätzen rein zu holen.
    Mach ich mir da selber nen Timer und les solange Daten ein, wie der Zähler läuft, und Teil dann mein Ergebnis durch die Anzahl Datensätze des Timers und multiplizier es dann mit dem Timer oder geht das einfacher?
    Hab da was von QueryPerformanceCounter gelesen.
    Geht das mit der Methode?
    Vielen Dank auf jeden Fall schonmal für das bisher, echt hammers cool. 👍 😃



  • Ich hab das in meine Recordset-Basisklasse gebastelt:

    bool CBasisSet::Query()
    {
    	BOOL fResult = FALSE;
    	DWORD dwAnfang = GetTickCount();
    
    	try
    	{
    		if(!IsOpen())
    		{
    			fResult = Open();
    		}
    		else
    		{
    			fResult = Requery();
    		}
    	}
    	catch (CDBException* e)
    	{
    		CLog::Log(LOG_NR_DB_FEHLER, e->m_strError);
    		throw(e); // Weiterwerfen
    	}
    
    	DWORD dwEnde = GetTickCount();
    	CLog::Log(LOG_NR_DB_QUERY, _T("Tabelle: %s"), GetDefaultSQL());
    	CLog::Log(LOG_NR_DB_QUERY, _T("Where: %s"), m_strFilter);
    	CLog::Log(LOG_NR_DB_QUERY, _T("Order by: %s"), m_strSort);
    	CLog::Log(LOG_NR_DB_QUERY, _T("Dauer: %d ms"), dwEnde-dwAnfang);
    	CLog::Log(LOG_NR_DB_QUERY, _T("Erfolg? %b"), fResult);
    
    	return (fResult == TRUE);
    }
    

    CLog::Log ist eine Art TRACE und CString::Format in eins. 🙂
    Irgendwer meinte aber mal, GetTickCount wäre zu ungenau. 🙄



  • Das würde mich auch interessieren 🙂

    Aber über ODBC kenne ich keine Möglichkeit dazu, auch deine Methode funktioniert nur ungenau. Je nachdem wie stark der DB-Server belastet ist benötigt er mehr oder weniger Zeit.. Ne abschätzung ist da ziemlich schwierig.
    Wenn die Rückgabe der Datenbank nicht sortiert sein soll, könnteste immer nur einen Teil der Daten holen und dabei nen Progressbar oder sowas aktualieren.
    Sobald du aber sortierst ("order by xxx") muss die Datenbank eh alles aufbereiten und du hast keinen Vorteil, im Gegenteil - es müsste bei jeder Anfrage wieder sortiert werden...



  • WOW cool!
    Nur ein wenig Erklärung brauch ich noch.
    Du startest einfach nen TickCount machst dann die Query und dann wieder den End-Tickcount und ziehst die dann von einander ab. richtig?
    Sprich wenn ich eine Query mach die 100 Datensätze liefert, dann nimm ich dwEnde-dwAnfang/100 und weiß wie lange er für einen Datesatz braucht und dann kann ich: Anzahl Ergebnisse * (dwEnde-dwAnfang/100) und es sollte in etwa die Zeit sein, die er benötigt um die Datensätze zu holen.
    😃 Wie cool! 😃



  • Ähm, ich glaube nicht, dass das linear steigt. Ich weiß es ehrlich gesagt nicht.

    Teste es doch mal. 😃
    Du brauchst aber wirklich große Datenmengen um da was rauszufinden.

    Aber sowas kann man ja mal eben mit einer Schleife produzieren. 🙂
    (Mein Programm für genau DEN Versuch ist leider weg...)



  • Also meine Zeit schwnakt wirklich stark, da ich zum Teil ja Daten aus dem Cache hole und zum Teil Daten von der Platte bekomme. Dazu kommt bei mir noch ob grad getestet wird, und wie das Netzwerk belastet ist. Diese Performance abfrage ist auch nur zum aufspüren von richtigen Server oder Netzwerk hängern. Also momentan schwanke ich bei 100 Datensätzen so zwischen 10 ms und 200 ms. 🙂
    Jetzt soll nur geschaut werden, wenn ich jetzt plötzlich 500ms oder gar 1000ms hab für 100 Datensätze, dann weiß ich dass da wohl was faul ist. Jetzt versuch ich mal 10 mal 10 Datensätze einzulesen und den Mittelwert daraus zu bilden. den Rechne ich dann auf die Anzahl Datensätze hoch.



  • kann ich irgendwie sagen gib mir die ersten matching 10 Datensätze? Falsch gefragt. Wie bekomme ich die ersten 10 Datensätze? weil dann kann ich per Zufallszahl in irgendeine ID einsteigen und von dort aus 10 Datensätze holen, um nicht immer die gleichen zu bekommen. Dass die wahrscheinlichkeit der Verteilung zwischen Cache und Platte möglichst groß ist.



  • AH vergesst das ganze mit der Zeit!!

    Die Zeit vor und nach Requery zu machen sagt nicht, dass ich solange brauche um alle Datensätze zu laden. Er sendet nur die Query etc und die DB sagt in der Zeit OK die Daten sind da. die Zeit bekomm ich aber nur wirklich raus wenn ich über meine ganzen Datensätze laufe die in meinem Recset sind. dann kann ich was darüber aussagen.

    Beispiel ich lade 10 Datensätze in meiner Query Dauer: = 170ms
    ich lade 8000 Datensätze in meiner Query Dauer: = 110 ms



  • Ist ja klar. Die Daten werden noch nicht abgerufen. Es wird nur ein Resultset erstellt.
    Willst du die Daten gleich abrufen musst du einen Snapshot erstellen.



  • Öhm ich arbeite mit nem Snapshot!

    m_nDefaultType = snapshot;
    

    Aber ist eh egal, entweder ich lass es ganz sein oder ich mach einfach mal nen Filter der 100 Datensätze enthält und dann moveLast, dann läuft er auch über alle Daten. wobei das leider nicht linear verläuft.

    100 Datensätze ≈ 200ms (bei meinem Netz usw.)
    1000 Datensätze ≈ 5800ms

    Klingt komisch ist aber so. 😃



  • Ist doch klar..

    mach doch einfach mal in deiner Commando-Zeile den Test, wenn du einfach nur nen "select * from tabelle" machst, dann isser sofort da - er liest die Daten dann wie sie physikalisch abgelegt wurden.
    bringst du nun noch ne where Klausel mit rein braucht er länger zum reagieren. Diese Zeit bekommst du zurück, oder? Und am längsten braucht er wenn du ihn noch sortieren lässt, dann ist auch egal ob du es auf die ersten 100 zeilen beschränkst..



  • Polofreak schrieb:

    Öhm ich arbeite mit nem Snapshot!

    m_nDefaultType = snapshot;
    

    Zumindest im Code sehe ich

    Set.Open(CRecordset::dynaset | CRecordset::forwardOnly, strSQL);
    

    ein dynaset



  • OK vielleicht einfach der vollständigkeit halber. Ich habe einen offenen Recset will den nicht schließen weil die Daten gerade angezeigt bleiben sollen, in der Zeit mach ich aber nen Count. Dazu stelle ich noch ne connection zur DB her drum hab ich einmal ein dynaset und einmal einen Snapshot. Die Zeiterfassung läuft momentan auf dem Snapshot. 🙄
    Eigentlich jetzt wo du es sagst, schwachsinn was ich da mach, ich könnte das auch gleich in die Abfrage die ich stelle mit rein bauen. Naja egal.
    Kann mir bitte einer sagen wie ich die ersten 1000 Datesätze einer Suchabfrage bekomme?


Anmelden zum Antworten