SQL Neuster Wert mit Timestamp ermitteln

Phoenixz

Lieutenant
Registriert
März 2004
Beiträge
595
Hi,

lang ist es her, dass ich mit SQL gearbeitet habe und entsprechend ist leider auch viel verloren gegangen. Ich habe folgende Situation bzw. meine Tabelle sieht wie folgt aus:

Timestamp, Name , Value

Ihr könnt euch vorstellen, das ich eine Art logger haben.

Nun möchte ich eine Abfrage erstellen, bei der ich den neusten Wert (Spalte "Value") von Spalte "Name" ermittele in Bezug auf die Spalte "Timestamp".

Beispiel (Nur ein Ausschnitt)

Timestamp, Name , Value
1, A, 10
2, A, 8
3, B, 4
4, A, 1
5, B, 10

soll folgendes ergeben

Timestamp, Name , Value
4, A, 1
5, B, 10

(Sowohl die Tabelle und die Werte sind natürlich ein abstraktes Beispiel und ein Timestamp ist natürlich keine Zahl, aber ich hoffe das Beispiel hilft trotzdem etwas)


Ich würde das jetzt wie folgt machen

SELECT max(Timestamp), Name
FROM MyTable
GROUP BY Name
INNER JOIN
...

Ich hoffe mein Grundgedanke ist klar ;).
Nun wollte ich fragen, ob das auch irgendwie "schöner" geht in Bezug auf die Geschwindigkeit. Da sind nämlich schon eine Menge Daten drin und da dann einen Join...

Vielen Dank!
Daniel
 
Eine Alternative wäre mit TOP 2 ... ORDER BY Timestamp DESC.
Ob es performanter ist weiß ich nicht aber du hast damit die Möglichkeit, mehrere Zeilen auszuwählen, so wie in deiner Beispielausgabe.
 
Hast du schon Keys für die Spalten vergeben? Das gibt ordentlich Performance, wenn deine Sortier-Spalten ebenfalls Keys haben.
 
Phoenixz schrieb:
Hi,

lang ist es her, dass ich mit SQL gearbeitet habe und entsprechend ist leider auch viel verloren gegangen. Ich habe folgende Situation bzw. meine Tabelle sieht wie folgt aus:

Timestamp, Name , Value

Ihr könnt euch vorstellen, das ich eine Art logger haben.

Nun möchte ich eine Abfrage erstellen, bei der ich den neusten Wert (Spalte "Value") von Spalte "Name" ermittele in Bezug auf die Spalte "Timestamp".

Beispiel (Nur ein Ausschnitt)

Timestamp, Name , Value
1, A, 10
2, A, 8
3, B, 4
4, A, 1
5, B, 10

soll folgendes ergeben

Timestamp, Name , Value
4, A, 1
5, B, 10

(Sowohl die Tabelle und die Werte sind natürlich ein abstraktes Beispiel und ein Timestamp ist natürlich keine Zahl, aber ich hoffe das Beispiel hilft trotzdem etwas)


Ich würde das jetzt wie folgt machen

SELECT max(Timestamp), Name
FROM MyTable
GROUP BY Name
INNER JOIN
...

Ich hoffe mein Grundgedanke ist klar ;).
Nun wollte ich fragen, ob das auch irgendwie "schöner" geht in Bezug auf die Geschwindigkeit. Da sind nämlich schon eine Menge Daten drin und da dann einen Join...

Erstmal ein kleiner Rat aus der Praxis: hör auf dir um Performance Gedanken zu machen, wenn du mit der Performance gar keine Probleme hast. Soll heißen: probier erstmal das erste was dir einfällt, wenns geht und es halbwegs pünktlich terminiert ist alles in Butter.

Mein Vorschlag wäre spontan: SELECT max(timestamp), value FROM tabelle WHERE name = ? GROUP BY value, ich sehe nicht so ganz was du da joinen willst? Das SQL ist ungetestet, aber sollte gehen (TM). Wenn du viel Zeug in der Tabelle hast, leg einen Index auf den Timestamp und den Namen, das sollte eigentlich schweinegut skalieren, egal wie groß dein Value wird.

Willst du alle Werte ist das analog: SELECT max(timestamp), name, value FROM tabelle group by name, value

Ich glaube du denkst hier zu kompliziert, mir hilft immer in Ergebnissen zu denken: Ein Abfrageergebnis mit Aggregatsfunktion im SELECT wird immer nur ein Ergebnis zurückliefern, und dieses Ergebnis ist ein exakt definiertes Ergebnistupel. Soll heißen wenn ich nach max(x) selektiere, bekomme ich ein Ergebnis wo X maximal ist und die entsprechenden anderen Werte die zu exakt dem Datensatz gehören bei dem eben x maximal ist ;)

Da ich nicht weiß in wie weit du dich auskennst: Indices. FALLS du mehr liest als du Datensätze schreibst (was bei einem Log der Fall sein sollte), dann leg einen Index auf den timestamp und falls du die Abfrage nach Name benutzt vielleicht auch einen auf den Namen, das mußt du ausprobieren: CREATE INDEX isdochmeineSachewieichmeinenIndexNenne ON tabelle(spaltenname)

Schreib mich an wenn noch was fehlt....
 
Hallo, Danke zunächst für die Antworten.

Ich habe nun das Problem so implementiert, wie von mir im ersten Post erwähnt. Was die Performance angeht, kann ich noch nicht so viel Sagen (aber wie bereits erwähnt, habe ich mir wohl zu viele Gedanken gemacht ^^). Viele Daten sind noch nicht in der Datenbank, die Abfrage dauert aktuell 8 Sekunden... sollte aber für den Zeitpunkt reichen - insb. da ich mir eigentlich ziemlich sicher bin, dass es nicht (sehr viel) besser geht (Das Beispiel zeigt nur eine starke Vereinfachung des Problems).
Zu deinem (@mambokurt) Vorschlag. Das klappt so nicht. Ich möchte ja quasi nach der Spalte Name (in dem Beispiel oben) gruppieren und dabei den Wert haben, der in der Zeile des maximalen Timestamp ist.

Die vollständige Abbfrage würde so aussehen:

SELECT
F.*
FROM
(SELECT
MAX(timestamp) AS timestamp
FROM
myTable
GROUP BY name) AS T
INNER JOIN
myTable as F
ON T. timestamp = F. timestamp

Ebenfalls onTheFly geschrieben, können also noch Fehler oder so drin sein ;). Bin der Meinung, dass es anders nicht geht, lasse mich aber gerne eines besseren Belehren.

Auch dein zweiter Vorschlag funktioniert übrigens nicht (SELECT max(timestamp), name, value FROM tabelle group by name, value), da ich ja nicht den value mit gruppieren will.

Trotzdem Danke für die ausführliche Antwort :)

Edit:
Achso, ja ich benutze einen MSSQL-Server. Aber wie schon gesagt, habe mir wohl einfach zu viele Gedanken darüber gemacht, was Performance angeht. Ist sowieso auch kein komerzielles Programm sondern eher eine kleine Spielerei für mich selbst...

Edit2:
Kleines Update, hab mich vertan. Er braucht für die komplette Abfrage nur zwei Sekunden ^^. Soviel zum Thema Performance. Damit wäre das Thema wohl gegessen. Trotzdem nochmal Danke :).
 
Zuletzt bearbeitet:
Deine Abfrage hat eine schwäche, es kann zu falsch ausgaben kommen,
sofern es zwei oder mehre datensätze gibt mit den gleichen timestamp.
Je nach auflösung des Timestamp ist es mehr oder weniger wahrscheinlich.

Lösung wäre nicht nur über timestamp zu joinen sondern auch über den namen.
 
Hast recht, an den Wert hatte ich gar nicht gedacht :D Ich weiß gerade nicht ob unter MSSQL JOIN oder Subselect schneller ist, man könnte sicherlich auch mal

Code:
SELECT *
FROM log
WHERE EXISTS (
SELECT 1
FROM (
SELECT max( time ) AS time, name
FROM log
GROUP BY name
)log2
WHERE log.time = log2.time
AND log.name = log2.name
)

Probieren, das könnte schneller laufen als der Riesenjoin. Ich habs hier unter MySQL ausgetestet, sollte aber eigentlich auch unter MSSQLlaufen...
 
Zurück
Oben