SELECT COUNT(*) optimieren

dcst55

Aktiver Benutzer
Beiträge
48
Hallo zusammen,

ich habe eine Diskussion darüber ob und wie man ein SELECT COUNT(*) einer Tabelle mit etwa 10 Mio. rows optimieren könnte.
Die Abfrage braucht etwa 2 Sekunden und wird etwa 600-700 mal täglich ausgeführt.

Die Idee ist, den Wert von count(*) in eine Hilfstabelle zu schreiben.
Beim anlegen neuer ROWS oder löschen bestehender ROWS wird mit einem TRIGGER der Wert in der Hilfstabelle erhöht oder entsprechend gesenkt.

Könnte es beim insert neuer ROWS zu Leistungseinbußen durch den TRIGGER kommen? oder ist die Idee grundsätzlich totaler Blödsinn?

Zudem haben wir ein count(*) mit einer WHERE FIND_IN_SET().. könnte man die auch mit einem ähnlichen Trigger optimieren?
SQL:
SELECT count(*) FROM Tabelle WHERE FIND_IN_SET('string', spalte)

Freue mich auf Eure Meinung.

LG
 
Zuletzt bearbeitet:
Werbung:
vermutlich ist die Idee völliger Bullshit weil i.d.R. keiner so genau wissen will oder muß, wie viele Rows in einer Tabelle sind. In vielen Fällen reichen Schätzwerte, diese würde ich (in PG) aus den Statistiken holen.

Wenn das count(*) mit einer WHERE-Condition ist wäre interessant zu wissen, wie selectiv diese Where-Condition ist. Dann könnte man evtl. über einen partiellen Index nachdenken. Im Falle MySQL kann man sich aber das nachdenken dann auch wieder sparen, weil es keine partiellen Indexe kennt. Falls Schätzwerte reichen, könnte man auch hier die Statistiken befragen. Oder table-sample - aber das kann MySQL glaube ich auch nicht.
 
Den Sinn möchte ich hier überhaupt nicht zur Diskussion stellen. Ich brauche den genauen Wert.
Sorry aber der DB-Server wird auch nicht zu PostgreSQL migrieren. Daher bringen mir die Lösungen mit PostgreSQL leider auch nichts.

Dennoch bedanke ich mich für Deine Gedankengänge, die werde ich im Hinterkopf behalten und beim nächsten Meeting mit den Applikationsentwicklern evtl. in den Raum werfen...
 
nimm halt MyISAM. Ist dann zwar nicht mehr transaktionsfest, aber ein count(*) ist da wohl sehr schnell...

Und ja, genauer Wert: Du hast 5 parallele Sessions in je einer Transaktion. In 2 werden Zeilen zugefügt, in 2 werden Zeilen gelöscht, in der restlichen machst Du Dein count(*)...
 
Freue mich auf Eure Meinung.
Also "genau" halte ich auch für eine ambitionierte Sache. So ähnlich wie mit Nachkommastellen der Außentemperatur oder so.

aber gut, Trigger machen es natürlich nicht schneller.

Und zu den Gedanken von akretschmer noch eine Ergänzung:
Selektivität könnte man noch ergänzen um die Frage, welcher Natur die Daten eigentlich sind oder besser, welches "Leben" sie führen. Börsenkurse, Messwerte, digital Twin Daten, ..
Mit etwas Glück hat man vielleicht nur in den letzten paar Monaten, entsprechend vielleicht 500T Datensätzen echte Bewegung. Die kann man exakt zählen. Den Rest selten und merken. Kleine SP und fertig.
Hilfreich sind darüber hinaus jede Art von bestehenden, indizierten Feldern zur Einschränkung, wie im Vorschlag zuvor also CreateDate, aber vielleicht auch Status, Land, ...
Partitionierung wäre wieder ein größerer Hammer..
 
Also natürlich macht ein Trigger den Schreibvorgang langsamer, wenn auch vermutlich nur sehr geringfügig. Um das sinnvoll abschätzen zu können brauchst du also nicht nur die Anzahl der durchgeführten Counts, sondern auch die Anzahl der Inserts (also Vorgänge, nicht Zeilen die durch den Vorgang betroffen sind). Wenn also nur fünf mal am Tag neue Datensätze in die Tabelle kommen aber 700 mal gezählt wird kannst du den Wert natürlich sinnvoll zwischenspeichern und beim Schreiben neuer Datensätze aktualisieren. Werden jetzt aber 100k Datensätze in einzelnen Transaktionen erzeugt würde ich den Trigger nicht nutzen.
 
ja, z.B. mit einem TIMESTAMP-Feld, welches das Insert-Datum enthält. Dann zählen, wie viele da sind. Allerdings sollte man keiner Statistik trauen, die man nicht selber gefälscht hat. Wenn Du 1000 Inserts und 999 Delete's hast würde 1 also Antwort je nach Ansicht falsch sein ...
 
Oder einfach erstmal einen Trigger erstellen der bei jedem INSERT, UPDATE, DELETE einen Log-Eintrag mit der Anzahl betroffener Datensätze befüllt. Der Trigger dürfte dann aber bei MySQL nicht ON EACH ROW feuern, oder wie das heißt, sondern nur einmal pro Vorgang.
 
nimm halt MyISAM. Ist dann zwar nicht mehr transaktionsfest, aber ein count(*) ist da wohl sehr schnell...

Und ja, genauer Wert: Du hast 5 parallele Sessions in je einer Transaktion. In 2 werden Zeilen zugefügt, in 2 werden Zeilen gelöscht, in der restlichen machst Du Dein count(*)...
Super Vorschlag,

damit hebelst du alle Vorteile von InnoDB aus. KEIN ROW LOCKING, nur noch table locking, KEINE TRANSAKTIONEN, KEINE FOREIGN KEYS, .... GUTE IDEE
 
Werbung:
Super Vorschlag,

damit hebelst du alle Vorteile von InnoDB aus. KEIN ROW LOCKING, nur noch table locking, KEINE TRANSAKTIONEN, KEINE FOREIGN KEYS, .... GUTE IDEE
Tja, man kann nicht alles haben ;-)

Ja, auch in PG dauert ein select count(*) entsprechend, weil ein sequential Scan nötig ist, um die Sichtbarkeit der Tupel in der aktuellen Transaktion zu prüfen.

Daher siehe auch #2
 
Zurück
Oben