Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   TUniQuery liefert falschen RecordCount (https://www.delphipraxis.net/177890-tuniquery-liefert-falschen-recordcount.html)

Andidreas 4. Dez 2013 09:21

Datenbank: SQLite • Version: ... • Zugriff über: UniDac

TUniQuery liefert falschen RecordCount
 
Hallo,

über eine TUniQuery mache ich einen ganz normalen
Code:
Select * From
auf eine SQLite Tabelle.
Wenn ich den RecordCount Abfrage liefert er mir ein falsches Ergebnis, mal sagt er ich habe 325 Datensätze in der Tabelle, mal 25, mal 850.
Die Tatsächlichen 870 Datensätze gibt er mir aber nie als RecordCount an.

Woran kann das liegen?

jaenicke 4. Dez 2013 09:57

AW: TUniQuery liefert falschen RecordCount
 
Wenn nicht alle Datensätze sofort abgerufen werden, "weiß" die Query noch gar nicht wie viele Datensätze es sind. Um das zu erzwingen kannst du (wenn es bei der Klasse dafür keine Einstellung gibt), ein Query.Last aufrufen und dann die Anzahl auslesen. Allerdings kann das eben ggf. auch deutlich länger dauern, wenn die Tabelle groß ist.

Bentissimo 4. Dez 2013 10:02

AW: TUniQuery liefert falschen RecordCount
 
Such mal in der UniDAC Hilfe nach "FetchRows". :wink:

jaevencooler 4. Dez 2013 10:10

AW: TUniQuery liefert falschen RecordCount
 
Moin, Moin,

Du kannst Dir auch mal die FetchOptions ansehen, da kannst Du einstellen wie die Daten von Deiner DB geholt werden sollen :

http://www.da-soft.com/anydac/docu/f...mfile=FAQ.html


Beste Grüße
Michael

Andidreas 4. Dez 2013 10:48

AW: TUniQuery liefert falschen RecordCount
 
Das mit den FetchRows habe ich auch gesehen...
Hier ist bei mir der Standard Wert von 25 eingetragen...

Das passt dann doch nicht zu den RecordCounts die mir die TUniQuery zurückliefert... oder doch?

Bernhard Geyer 4. Dez 2013 11:04

AW: TUniQuery liefert falschen RecordCount
 
Zitat:

Zitat von Andidreas (Beitrag 1238484)
Das passt dann doch nicht zu den RecordCounts die mir die TUniQuery zurückliefert... oder doch?

Doch. Deine Werte sind vielfache von 25 und der liefert dir die Anzahl der schon geholten Einträge.

Perlsau 4. Dez 2013 14:40

AW: TUniQuery liefert falschen RecordCount
 
Zitat:

Zitat von jaenicke (Beitrag 1238469)
... ein Query.Last aufrufen und dann die Anzahl auslesen.

Daneben bieten die Query-Komponenten von DevArt die Möglichkeit, in den Options das Property QueryRecCount auf True zu setzen. Damit wird bei jedem Select die Anzahl der Datensätze ermittelt. Kann natürlich ebenso wie ein Query.Last etliche Zeit in Anspruch nehmen.

Eine dritte Möglichkeit bestünde darin, in einer gesonderten Tabelle den RecordCount aller anderen Tabellen zu verwalten, eventuell mit einer StoredProcedure auf dem Laufenden halten ...

nahpets 4. Dez 2013 15:01

AW: TUniQuery liefert falschen RecordCount
 
Wenn ich den RecordCount einer Tabelle zwingend korrekt benötige mache ich einfach ein:
Code:
select count(*) as Anzahl from Tabelle
Das in einer extra Tabelle zu verwalten dürfte schnell recht aufwändig werden, da jedes Insert oder Delete dann diesen Verwaltungsschritt auslösen müsste und dann letztlich auch nur das Ergebnis des obigen SQL je Tabelle in der Verwaltungstabelle speichern müsste.

Perlsau 4. Dez 2013 15:36

AW: TUniQuery liefert falschen RecordCount
 
Zitat:

Zitat von nahpets (Beitrag 1238506)
Wenn ich den RecordCount einer Tabelle zwingend korrekt benötige mache ich einfach ein:
Code:
select count(*) as Anzahl from Tabelle

Und das wäre dann aus welchem Grund schneller als ein Query.Last?

Zitat:

Zitat von nahpets (Beitrag 1238506)
Das in einer extra Tabelle zu verwalten dürfte schnell recht aufwändig werden, da jedes Insert oder Delete dann diesen Verwaltungsschritt auslösen müsste und dann letztlich auch nur das Ergebnis des obigen SQL je Tabelle in der Verwaltungstabelle speichern müsste.

Bei einer Tabelle mit zahlreichen Spalten (große VarChars und etliche Blobs) und Millionen von Datensätzen kann das aber schon Geschwindigkeitsvorteile bringen, wenn es um das Ermitteln des RecordCount geht, denn es würde das Durchzählen ersparen. Was spräche denn dagegen, mittels entsprechender StoredProcedures, die von den Triggern AfterInsert und AfterDelete ausgelöst werden, diesen einen Eintrag vorzunehmen? Man könnte auf diese Weise sogar den RecordCount aller Tabellen auf dem aktuellen Stand halten, wenn es notwendig wäre. Ich bin mir sicher, daß bei sehr großen Datenbanken (z.B. denen der NSA oder auch denen der EU-Vorratsdatenspeicherung) solche Mechanismen angewendet werden.

DeddyH 4. Dez 2013 15:41

AW: TUniQuery liefert falschen RecordCount
 
Das kann ich mir nicht vorstellen. So etwas würde ja nur in solchen Datenbanken ansatzweise Sinn ergeben, die sehr oft abgefragt, aber eher selten aktualisiert werden. Alle anderen würden hingegen vermutlich merklich ausgebremst werden, da für jeden einzelnen zu löschenden oder einzufügenden Datensatz der Trigger feuern würde.

mkinzler 4. Dez 2013 15:42

AW: TUniQuery liefert falschen RecordCount
 
Zitat:

Und das wäre dann aus welchem Grund schneller als ein Query.Last?
Beim Query.Last muss die gesamte Abfrage mit allen Records und allen Feldern an den Client übertragen werden.
Bei der exlpziten Abfrage wird die Anzahl am Server ermittelt, was sehr schnell gehen sollte.
Bei einem richtigen DBMS werden entsprechende Verwaltungstabellen vom Server automatisch angelegt und gepflegt; diese redundant selber anzulegen und den Server mit der doppelten Pflege zu belasten ist imho nicht notwendig.

Andidreas 4. Dez 2013 16:15

AW: TUniQuery liefert falschen RecordCount
 
Zitat:

Zitat von Perlsau (Beitrag 1238504)
Zitat:

Zitat von jaenicke (Beitrag 1238469)
... ein Query.Last aufrufen und dann die Anzahl auslesen.

Daneben bieten die Query-Komponenten von DevArt die Möglichkeit, in den Options das Property QueryRecCount auf True zu setzen. Damit wird bei jedem Select die Anzahl der Datensätze ermittelt. Kann natürlich ebenso wie ein Query.Last etliche Zeit in Anspruch nehmen.

Eine dritte Möglichkeit bestünde darin, in einer gesonderten Tabelle den RecordCount aller anderen Tabellen zu verwalten, eventuell mit einer StoredProcedure auf dem Laufenden halten ...

Merci, damit klappts und ist für mich im Moment die beste Lösung...

Ist dieses Verhalten eigentlich Komponenten abhängig?

Mir ist dieses "komische" Verhalten heute zum ersten mal aufgefallen und die TUniDac Komponenten verwende ich noch nicht so lang!
Bei den ADO Komponenten oder MyDAC Komponenten ist mir das bis jetzt zumindest noch nicht aufgefallen...

jaenicke 4. Dez 2013 16:26

AW: TUniQuery liefert falschen RecordCount
 
Zitat:

Zitat von mkinzler (Beitrag 1238513)
Beim Query.Last muss die gesamte Abfrage mit allen Records und allen Feldern an den Client übertragen werden.
Bei der exlpziten Abfrage wird die Anzahl am Server ermittelt, was sehr schnell gehen sollte.

Das geht nicht unbedingt schnell. Wenn man mit join usw. arbeitet, würde eine separate Abfrage von count(*) dazu führen, dass die gesamte Abfrage ggf. doppelt erzeugt werden muss. Da sollte der Cache zwar helfen, aber es ist trotzdem unnötig.

Bei einfachen Tabellen kann man natürlich count(*) benutzen und es geht auch meistens schnell (leider nicht immer...). Aber wirklich Sinn macht das trotzdem nur, wenn die Datenmengen so groß sind, dass ein Last zu lange braucht.

Nebenbei gibt es z.B. bei MS SQL Server auch noch nette Features wie Histogrammerzeugung für die Wertverteilung in den Indexspalten, mit denen man z.B. ein Nachladen im Thread sehr gut implementieren kann.

// EDIT:
Zitat:

Zitat von Andidreas (Beitrag 1238521)
Ist dieses Verhalten eigentlich Komponenten abhängig?

Die BDE hat sowas z.B. nicht gemacht, und auch andere lokal dateibasierte Datenbanksysteme machen das oft nicht so.

hstreicher 4. Dez 2013 19:06

AW: TUniQuery liefert falschen RecordCount
 
diese ganze Count's sind eigentlich nur Kaffeesatzlesen , denn die Datenbanken sind Multiuser
und waehrend sich der Count-Thread abquaelt können hinten 1000 Records gelöscht worden sein ,
oder vorne 1000 dazukommen
dazu reicht ein einfaches Commit;

mfg Hannes

Perlsau 4. Dez 2013 19:35

AW: TUniQuery liefert falschen RecordCount
 
Zitat:

Zitat von hstreicher (Beitrag 1238540)
diese ganze Count's sind eigentlich nur Kaffeesatzlesen , denn die Datenbanken sind Multiuser
und waehrend sich der Count-Thread abquaelt können hinten 1000 Records gelöscht worden sein ,
oder vorne 1000 dazukommen
dazu reicht ein einfaches Commit;

Auch wenn du dir in deiner Polemik gefällst, paßt da so einiges nicht, denn:

1. Nicht jede Datenbank wird ständig von mehreren Usern in Anspruch genommen, viele sogar immer nur von einem User. Was genau für die DB des TE zutrifft, mußt du ihn selbst fragen, was für das Problem des TE aber vollkommen irrelevant ist.

2. Ein Count, egal woher, zeigt immer nur die aktuelle Anzahl der vorhandenen Records, auch wenn dieser Wert sich bei manchen Datenbanken sehr schnell ändern kann. Deswegen ist das noch lange keine Kaffeesatzleserei, was ja bedeuten würde, der Wert würde erraten oder basiere auf irgendwelchen esoterischen Tricks.

3. Deiner Ansicht nach dürfte man wohl niemals danach fragen, wie viele Datensätze in einer Tabelle gerade gespeichert sind. Ist irgendwie so wie mit dem Putzen: Wenn man sich mit der Ausrede, daß die Treppe ja sowieso wieder dreckig würde, ständig darum drückt, sie zu wischen, geht man eines Tages auf einer zentimeterdicken Dreckschicht. Oder gibt es deiner Ansicht nach keinen vernünftigen Grund, die Anzahl der vorhandenen Datensätze ermitteln zu wollen? Wenn doch, wäre es interessant zu lesen, wie du diesen Wert ermitteln würdest.

nahpets 4. Dez 2013 22:44

AW: TUniQuery liefert falschen RecordCount
 
Zitat:

Zitat von hstreicher (Beitrag 1238540)
diese ganze Count's sind eigentlich nur Kaffeesatzlesen , denn die Datenbanken sind Multiuser
und waehrend sich der Count-Thread abquaelt können hinten 1000 Records gelöscht worden sein ,
oder vorne 1000 dazukommen
dazu reicht ein einfaches Commit;

mfg Hannes

na, wenn dem so ist, dann ist auch ein Last Kaffeesatzlesen, denn in der Zeit, in der der Client die Daten von der Datenbank empfängt, können andere Nutzer 1000e von Datensätzen hinzufügen, ändern oder entfernen.
Man sieht in allen Fällen nur das, was in der eigenen Session ist, bis zum nächsten eigenen Commit oder Rollback. Erst danach kann man den dann aktuellen Stand der DB abfragen, der zu diesem Zeitpunkt per Commit oder Rollback aller Nutzer festgeschrieben ist. Man erhält immer nur eine Momentaufnahme, da zeitgleich andere Änderungen an den Daten vornehmen können.
Unter diesen Bedingungen ist also letztlich jede Abfrage nur eine Art "Kaffeesatzlesen". Und das sollte jedem, der keinen Exklusivzugriff auf eine Datenbank hat, klar sein.

Ob in RecordCount letztlich ein "korrekter" Wert steht ist datenbankabhängig. Manche Datenbank liefert diesen Wert sofort, andere nicht. Häufig enthält RecordCount die Anzahl der Sätze, die bisher per Fetch an den Client geliefert wurden. Die Datenbank weiß zu diesem Zeitpunkt nicht zwingend schon, wie groß die Satzzahl der Abfrage sein wird, da sie immer nur soviele Datensätze der Ergebnismenge ermittelt, wie per Fetch angefordert wurden. Zum Zeitpunkt der Lieferung der ersten Daten der Ergebnismenge muss eine Abfrage noch lange nicht über die gesamten Ergebnismenge verfügen, also vollständig ausgeführt sein. D. h.: Der Wert für RecordCount ist der Datenbank auch nicht unbedingt jederzeit bekannt, aber das ist datenbankabhängig. Auch das Verhalten der einzelnen Datenbankkomponenten ist hier unterschiedlich.

jobo 5. Dez 2013 07:12

AW: TUniQuery liefert falschen RecordCount
 
Ein Select count(*) sollte in jedem Fall(!) schneller sein, als das vollständige Laden (Last) der Daten auf den Client. Selbst wenn es eine lokale DB ist, muss an dieser Stelle die Datenmenge von der DB-Datei mindestens in den Anwendungsspeicher übertragen werden.
Eine halbwegs schlaue Implementierung bzw. Optimierung einer Count(*) Anfrage wird außerdem nicht die Datenmenge aufbauen (wozu, wollte keiner wissen), sondern nur die join - und where Kriterien prüfen und zählen.
Und das sollte jedes am Markt etabliertes RDBMS sehr gut können. Genauer gesagt, sollte jeder Server selbst am besten wissen, wie er die exakte Ergebnismenge so schnell wie möglich bestimmt. Das vollständige Laden und Durchzählen am Client ist dagegen brute force. (Wenn ich weiß, dass ich auf jeden Fall alle diese Daten brauche, ist es natürlich egal bzw. sinnlos, sie separat per Count zu zählen)
Sinnlos ist eine eigene Verwaltung von Datenmengen. Dieses Rad wurde schon erfunden und zwar von den Anbietern der RDBMS, spätestens beim ersten Join nützt die Eigenimplementierung wohl eh nichts.
Ich beziehe mich damit auf echte RDBMS, keine BDE, ISAM usw Systeme.

P.S.: Ich kann auch in einem SingleUser System ohne Probleme verschiedene Counts zustande bringen, sobald ich mit getrennten Connections/Transaktionen arbeite, threaded, .. arbeite. Beispielsweise bei einem Datenimport im Hintergrund, der dummerweise vielleicht sogar noch mit Teilcommits. implementiert ist.

p80286 5. Dez 2013 10:31

AW: TUniQuery liefert falschen RecordCount
 
Zitat:

Zitat von hstreicher (Beitrag 1238540)
diese ganze Count's sind eigentlich nur Kaffeesatzlesen

Wenn man glaubt, daß da verläßliche Daten für die nächsten ...Minuten/Stunden/Tage herum kommen. Wenn eine Query 1234 Datensätze liefert, dann ist das eine Momentaufnahme, ein einfaches distinct kann da schon die zurück gelieferte Datenmenge auf ein viertel oder weniger schrumpfen lassen, und wenn das bei einem "select * from tabelle" der Fall ist, sollte man sein DB-Design einmal überprüfen.

Zumindestens unter Oracle ist ist ein count(irgendwas) immer wesentlich schneller als ein .last. und wenn's unbedingt nötig ist kann man ja beim Auslesen mitzählen.

Gruß
K-H


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:33 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz