Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Select Count(*) vs. Select First 1 (https://www.delphipraxis.net/192839-select-count-%2A-vs-select-first-1-a.html)

TigerLilly 24. Mai 2017 10:40

AW: Select Count(*) vs. Select First 1
 
Wenn(!) ein Full Table Scan notwendig ist, dann ist er das bei Count(*) Count(1) first 1 auch.
Es ist wirklich egal + es gibt kein Szenario, wo eines schneller wäre.

Und Achtung: wir reden hier von FB und nicht dBase. :-)

jobo 24. Mai 2017 11:38

AW: Select Count(*) vs. Select First 1
 
Wieso sollte ein First in FB und ohne Angabe von Order by nicht schneller sein?
Ich habe selber schon geschrieben, dass es natürlich eine Frage der Implementierung ist, aber es würde sehr viel Sinn machen, nach der verlangten Anzahl Datensätze abzubrechen. Das kann count nicht.

Poelser 24. Mai 2017 12:00

AW: Select Count(*) vs. Select First 1
 
Wenn FB (nutze ich allerdings nicht) einen SELECT FIRST 1 ohne Order By zulässt, dann ist das sicher schneller. Ich hatte mit ASA (welches eben Order By braucht) die schnellsten Ergebnisse mit SELECT 1 FIRST 1 ORDER BY 1. Das funktionierte rattenschnell, und zwingt auch dazu, die erste Spalte als PK-Spalte zu haben:-)

hoika 24. Mai 2017 15:05

AW: Select Count(*) vs. Select First 1
 
Hallo,
Zitat:

Adaptive Server Anywhere z.B. meckert beim First rum, dass das Ergebnis nicht deterministisch sein würde. Zurecht, denn die DB-Engine weiß ja nicht, dass mir der Inhalte des zurückgelieferten Datensatzes in diesem Fall egal ist.
Das habe ich gar nicht verstanden

Ich mache ein Select First 1 Id From Table1, das liefert mit den ersten Werte des Feldes Id, Reihenfolge ist hier auch egal.

Ich hatte irgendwo auch mal gelesen, dass Exists hier noch schneller ist:
Select 1 From RDB$DataBase Where Exists (Select First 1 Id From Table1)
Durch das Exists wird wohl noch schneller gesucht.

http://www.janus-software.com/fbmanu...=psql&topic=85

Ja, ich weiss er vergleicht mit Count(*).

jobo 24. Mai 2017 16:05

AW: Select Count(*) vs. Select First 1
 
Zitat:

Zitat von hoika (Beitrag 1372658)
Ich mache ein Select First 1 Id From Table1, das liefert mit den ersten Werte des Feldes Id, Reihenfolge ist hier auch egal.

Ich hatte irgendwo auch mal gelesen, dass Exists hier noch schneller ist:
Select 1 From RDB$DataBase Where Exists (Select First 1 Id From Table1)
Durch das Exists wird wohl noch schneller gesucht.

Die Kernanmerkung (Unterschied zu FB FIRST) bei adaptive ist ja wohl, das adaptive das FIRST nur akzeptiert, wenn ein ORDER dabei ist. M.E. eine etwas schwache (oder pingelige) Implementierung. Wenn FB das FIRST ohne ORDER akzeptiert, tut es genau das, wozu es nach Deiner Anforderung in diesem THREAD eingesetzt wird.
(Würde man ein ORDER hinter das FIRST packen, käme vielleicht ein anderer Datensatz an erster Stelle, das Order zwingt aber genau wie das COUNT zu einer vollständigen Suche)
Es geht aber nur darum, ob 1 Datensatz EXISTiert.


Womit wir bei der EXIST Variante wären. Das Beispiel das Du anführst ist m.E. doppelt gemoppelt. Die Arbeit macht das FIRST Statement am Ende in Klammern. Das nochmal mit EXISTS abzufragen, bringt m.E. gar nichts. (Den Zusatzaufwand die Rückgabe von FIRST erneut zu prüfen, mal vernachlässigt, ansonsten wäre die Kombi EXISTS plus FIRST m.E. marginal sogar langsamer)

TigerLilly 24. Mai 2017 17:44

AW: Select Count(*) vs. Select First 1
 
Das hat früher mal gestimmt, aber heute nicht mehr. Moderne query analyzer - und FireBird hat so was - erkennen diese Situationen und erzeugen idente execution plans.
Für ASA mag das nicht oder anders gelten, es implementiert den SQL92 Standard nicht vollständig.
Es gilt aber sicher für MS-SQL, Oracle, IB, FB.

Ob Tuning in einem solchen Bereich überhaupt Sinn hätte, wäre halt auch zu überlegen.

jobo 24. Mai 2017 19:41

AW: Select Count(*) vs. Select First 1
 
Na, wenn die das alle können, worüber reden wir dann?
Ein Optimizer kann m.E. nicht unterscheiden, ob ich über ein Count(*) nur wissen will, ob ein Datensatz da ist oder wirklich die Zahl haben will. Er kann nicht anders, als davon ausgehen, dass die korrekte Zahl benötigt wird.
Ob dann vorne dran noch ein Exists hängt oder was auch immer, geschenkt.

Neben der ganzen Tuning Diskussion bis jetzt, die sich "um die Spitze des Eisbergs" dreht, das Endergebnis von Count versus First usw. ist wahrscheinlich viel bedeutender, wie die Where Clause dahinter aussieht. Wenn das einigermaßen Index basiert durchläuft, ist es vermutlich irrelevant, ob ein Count=3 oder 15 rauskommt und ein First 1 statt dessen folglich 14 Indexzugriffe sparen täte.

Bei der Where Clause kann sich ein Optimizer prima austoben und ich behaupte mal, auch heute schadet notfalls etwas Analyse und ein paar Experimente nicht. Dass ein (auch moderner) Opensource Optimizer an MSSQL oder Oracle DB rankommt, wage ich allerdings zu bezweifeln.

p80286 24. Mai 2017 21:15

AW: Select Count(*) vs. Select First 1
 
Zitat:

Zitat von hoika (Beitrag 1372597)
Hallo,
bei einer üblichen Performance-Analyse sehe ich mal wieder alten Code mit dem üblichen Select Count(*) .

Was für eine Performance?
Falls das Count wirklich auf dem Client stattfinden sollte, was ich für einige DBMS ausschließen kann, mißt Du hier eine fröhliche Summe von Einflußfaktoren. Wenn das Ergebnis nicht schnell genug zur Verfügung steht, kann alles mögliche hierauf Einfluß haben.
Wird das Count auf dem Server ausgeführt, hat man zumindest eine Näherung zu was die DB auf dem Server bei der augenblicklichen Konfiguration in der Lage ist.

Gruß
K-H

Zumindest bei den mir zur Verfügung stehenden Oracle-DB ist Count(*) immer sauschnell 10 Mio-Datensätze <3 sec
Was leider keine Aussage über die Datenbereitstellung anderer Abfragen erlaubt.

IBExpert 24. Mai 2017 21:18

AW: Select Count(*) vs. Select First 1
 
Zitat:

Zitat von TigerLilly (Beitrag 1372668)
Ob Tuning in einem solchen Bereich überhaupt Sinn hätte, wäre halt auch zu überlegen.

Naja, das Tuning generell ist schon extrem hilfreich, je größer die DB um so eher bringt das was, zumindest
bezogen auf firebird.

Da ich aber die unterschiedlichen Varianten auch schon hier und da gehört hab, reizte es mich dann doch gerade
mal das mit geprüften Fakten zu bereichern.

Ergebnisse: Wenn eine "where xxx = ..." Bedingung mit 0 oder 1 Ergebnissen auf einem indizierten Feld benutzt wird, sind
alle Varianten (count(*), count(id), count(1), first 1) gleich schnell (siehe code beispiel unten)

Sobald die where Bedingung aber mehr als einen Datensatz liefert bzw Datensätze, die nicht auf einer Page
sind und man nur wissen muss das mindestens einer da ist oder nicht da ist, rechnet sich ein exists oder
insbesondere auch not exists sehr schnell, weil dann eben nicht weiter gesucht werden muss.

Die Datentypen selber haben aber auch indiziert erheblichen Einflus auf den speed

100000 randomsuche mit where indiziert auf bigint= ca 810 ms
100000 randomsuche mit where indiziert auf varchar(80) mit avg char_length 9= ca 1170 ms
100000 randomsuche mit where indiziert auf varchar(800) mit avg char_length 192= ca 4500 ms

Es gibt aber noch viel mehr Dinge, die man optimieren sollte, und teilweise sind die ganz
banal und erschreckend unlogisch, zB where Bedingung auf Feldern mit schlechter Selektvität,
Like in Prozeduren wenn parameter benutzt werden uvm.




Code:
execute block
as
declare variable i integer;
declare variable xx integer;
declare variable anz integer;
begin


  i=100000;
  while (i>0) do
  begin
    i=i-1;
    xx=rand()*100000;
    --v1  suchen über count(*)                828 ms  812 ms 828 ms
    --select count(*) from test where id=:xx into anz;
    --v2  suchen über count(id)               813ms 813ms 813ms
    --select count(*) from test where id=:xx into anz;
    --v3  suchen über count(1)                828 ms 828 ms 813ms
    --select count(1) from test where id=:xx into anz;
    --v4  suchen über first 1 id              797 ms 813 ms 812ms
    --select first 1 id from test where id=:xx into anz;
    --v5 suche über txt varchar(80) indiziert 1172 ms 1172 ms 1157 ms
    --select count(*) from test where txt='TXT2_'||:xx into anz;
    --v6 suche über txt2 varchar(800) indiziert 4531 ms 4421 ms 4422 ms
    --select count(*) from test where txt='TXT2_'||:xx||:xx||'TXT2_'||:xx||:xx||'TXT2_'||:xx||:xx||'TXT2_'||:xx||:xx||'TXT2_'||:xx||:xx||'TXT2_'||:xx||:xx||'TXT2_'||:xx||:xx||'TXT2_'||:xx||:xx||'TXT2_'||:xx||:xx||'TXT2_'||:xx||:xx||'TXT2_'||:xx||:xx||'TXT2_'||:xx||:xx||'TXT2_'||:xx||:xx into anz;
  end
end


/*
CREATE TABLE TEST (
    ID   BIGINT NOT NULL,
    TXT  VARCHAR(80),
    TXT2  VARCHAR(800)
);

ALTER TABLE TEST ADD PRIMARY KEY (ID);

CREATE INDEX TEST_IDX1 ON TEST (TXT);
CREATE INDEX TEST_IDX2 ON TEST (TXT2);



Daten in der Tabelle

ID;TXT;TXT2
0;"TXT2_0";"TXT2_00TXT2_00TXT2_00TXT2_00TXT2_00TXT2_00TXT2_00TXT2_00TXT2_00TXT2_00TXT2_00TXT2_00TXT2_00"
1;"TXT2_1";"TXT2_11TXT2_11TXT2_11TXT2_11TXT2_11TXT2_11TXT2_11TXT2_11TXT2_11TXT2_11TXT2_11TXT2_11TXT2_11"
2;"TXT2_2";"TXT2_22TXT2_22TXT2_22TXT2_22TXT2_22TXT2_22TXT2_22TXT2_22TXT2_22TXT2_22TXT2_22TXT2_22TXT2_22"
3;"TXT2_3";"TXT2_33TXT2_33TXT2_33TXT2_33TXT2_33TXT2_33TXT2_33TXT2_33TXT2_33TXT2_33TXT2_33TXT2_33TXT2_33"
4;"TXT2_4";"TXT2_44TXT2_44TXT2_44TXT2_44TXT2_44TXT2_44TXT2_44TXT2_44TXT2_44TXT2_44TXT2_44TXT2_44TXT2_44"
5;"TXT2_5";"TXT2_55TXT2_55TXT2_55TXT2_55TXT2_55TXT2_55TXT2_55TXT2_55TXT2_55TXT2_55TXT2_55TXT2_55TXT2_55"
6;"TXT2_6";"TXT2_66TXT2_66TXT2_66TXT2_66TXT2_66TXT2_66TXT2_66TXT2_66TXT2_66TXT2_66TXT2_66TXT2_66TXT2_66"
7;"TXT2_7";"TXT2_77TXT2_77TXT2_77TXT2_77TXT2_77TXT2_77TXT2_77TXT2_77TXT2_77TXT2_77TXT2_77TXT2_77TXT2_77"
8;"TXT2_8";"TXT2_88TXT2_88TXT2_88TXT2_88TXT2_88TXT2_88TXT2_88TXT2_88TXT2_88TXT2_88TXT2_88TXT2_88TXT2_88"
9;"TXT2_9";"TXT2_99TXT2_99TXT2_99TXT2_99TXT2_99TXT2_99TXT2_99TXT2_99TXT2_99TXT2_99TXT2_99TXT2_99TXT2_99"
10;"TXT2_10";"TXT2_1010TXT2_1010TXT2_1010TXT2_1010TXT2_1010TXT2_1010TXT2_1010TXT2_1010TXT2_1010TXT2_1010TXT2_1010TXT2_1010TXT2_1010"
11;"TXT2_11";"TXT2_1111TXT2_1111TXT2_1111TXT2_1111TXT2_1111TXT2_1111TXT2_1111TXT2_1111TXT2_1111TXT2_1111TXT2_1111TXT2_1111TXT2_1111"
....
insgesamt 100000 records
....
99.997;"TXT2_99997";"TXT2_9999799997TXT2_9999799997TXT2_9999799997TXT2_9999799997TXT2_9999799997TXT2_9999799997TXT2_9999799997TXT2_9999799997TXT2_9999799997TXT2_9999799997TXT2_9999799997TXT2_9999799997TXT2_9999799997"
99.998;"TXT2_99998";"TXT2_9999899998TXT2_9999899998TXT2_9999899998TXT2_9999899998TXT2_9999899998TXT2_9999899998TXT2_9999899998TXT2_9999899998TXT2_9999899998TXT2_9999899998TXT2_9999899998TXT2_9999899998TXT2_9999899998"
99.999;"TXT2_99999";"TXT2_9999999999TXT2_9999999999TXT2_9999999999TXT2_9999999999TXT2_9999999999TXT2_9999999999TXT2_9999999999TXT2_9999999999TXT2_9999999999TXT2_9999999999TXT2_9999999999TXT2_9999999999TXT2_9999999999"


*/

IBExpert 24. Mai 2017 21:34

AW: Select Count(*) vs. Select First 1
 
Zitat:

Zitat von p80286 (Beitrag 1372688)
Zumindest bei den mir zur Verfügung stehenden Oracle-DB ist Count(*) immer sauschnell 10 Mio-Datensätze <3 sec
Was leider keine Aussage über die Datenbereitstellung anderer Abfragen erlaubt.

Das ist an sich noch nichts wo man vor Erfurcht zusammenbrechen muss ...

Leider benutzen viele Kunden irgendwelche Server, die irgendwas sicher auch ganz schnell können,
aber für Firebird kompletter Schrott sind und trotzdem sauteuer.

Wenn man die dann mit sauteuren uund hochoptimierten Oracle oder MSSQL Servern vergleicht,
kommt da nichts bei raus. Und frag am besten weder Dell, HP noch Lenovo nach geeigneter
Firebird Hardware, die Systemhäuser stellen da nur teuren Quatsch zusammen.

Diesen Test hab ich gerade auf einer Kunden DB gemacht, count(*) für ca 3mio Datensätze
in ca. 0,6 Sekunden

Die Serverhardware ist von uns geliefert, kostet mit 1TB ca 3500 € und schafft
einen IBExpert Firebird Benchmark von >=500% Driveindex und >=300% CPU Index
und ist transaktionsecht live auf einer zweiten baugleichen Maschine repliziert.

Vermutlich ab nächste Woche bieten wir die auch wieder außerhalb von Kundenprojekten an
und im Herbst machen wir damit vermutlich mal wieder eine Roadshow.


Code:

query:

Select count(*) from brpst

COUNT
2979487

Plan
PLAN (BRPST NATURAL)

------ Performance info ------
Prepare time = 16ms
Execute time = 625ms
Avg fetch time = 625,00 ms
Current memory = 1.171.921.280
Max memory = 0
Memory buffers = 40.000
Reads from disk to cache = 6.955
Writes from cache to disk = 2
Fetches from cache = 0


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:56 Uhr.
Seite 2 von 3     12 3      

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