Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   paged query im Eigenbau? (https://www.delphipraxis.net/180813-paged-query-im-eigenbau.html)

bernhard_LA 19. Jun 2014 16:08

Datenbank: MSSQL • Version: 2012 • Zugriff über: ADO

paged query im Eigenbau?
 
wenn ich mir Daten vom Server in kleinen Portionen holen will könnte ich entweder Paged Queries

Delphi-Quellcode:
SELECT * FROM ( 
  SELECT *, ROW_NUMBER() OVER (ORDER BY name) as row FROM sys.databases
 ) a WHERE a.row > 5 and a.row <= 10
oder in unserem Falls, da die meisten Tabellen auch ein "ziemlich fortlaufendes " Feld "RecordID" besitzen auf

Delphi-Quellcode:
select * from Mytable where recordID < MaxId and recordID>MinId


zurückgreifen.

Ist zwischen einer "paged-Query" und dem Eigenbau ein Unterschied bzgl. der Performance zu erwarten ?

Namenloser 19. Jun 2014 16:47

AW: paged query im Eigenbau?
 
Sorry für den möglicherweise dummen Beitrag, aber kann man das, was du da machst, nicht möglicherweise mit dem
Delphi-Quellcode:
LIMIT
-Befehl einfacher lösen? Der ist doch eigentlich genau für „paged queries“ gedacht.

bernhard_LA 19. Jun 2014 16:54

AW: paged query im Eigenbau?
 
LIMIT geht leider nicht für MSSQL

Blup 19. Jun 2014 17:03

AW: paged query im Eigenbau?
 
Halte ich beides nicht für sinnvoll, bei einer Query werden doch normalerweise nur so viele Datensätze geholt, wie mit Next auch angefordert?

Uwe Raabe 19. Jun 2014 17:05

AW: paged query im Eigenbau?
 
Bei MSSQL gibt es OFFSET und FETCH in der ORDER BY Klausel.

Dejan Vu 19. Jun 2014 18:19

AW: paged query im Eigenbau?
 
Ab SQL-Server 2012 geht das so:
SQL-Code:
SELECT * from Tabelle
ORDER BY PrimaryKeyPreferablyWithAClusteredIndex
OFFSET @page*@windowSize ROWS
FETCH NEXT @windowSize ROWS ONLY

himitsu 19. Jun 2014 19:30

AW: paged query im Eigenbau?
 
Arbeiten ordentliche DBMS mit passenden SQL-Komponenten nicht eh schon stückchenweise?
(auch entsprechend der Antwort von Blup)

z.B. pgDAC und Co. und (bestimmt) auch DBX/DataSnap laden die Datensätze nur stückchenweise nach, es sei denn man aktiviert eine Option, um die Daten alle sofort laden zu lassen.

Auch ordentliche DBGrids haben einen Modus, um möglichst nur die angezeigten Datensätze zu laden und nicht gleich alles in den eigenen Cache zu kopieren. (nur gibt es dann natürlich oftmals keine Sortierung oder Filterung mehr)

Dejan Vu 19. Jun 2014 20:55

AW: paged query im Eigenbau?
 
Zitat:

Zitat von himitsu (Beitrag 1262934)
Arbeiten ordentliche DBMS mit passenden SQL-Komponenten nicht eh schon stückchenweise?
(auch entsprechend der Antwort von Blup)

Nope. Und selbst wenn. Die Kleinigkeit kann man nun wirklich selbst bauen.

Zitat:

Auch ordentliche DBGrids haben einen Modus, um möglichst nur die angezeigten Datensätze zu laden und nicht gleich alles in den eigenen Cache zu kopieren. (nur gibt es dann natürlich oftmals keine Sortierung oder Filterung mehr)
Wozu das Grid, wenn die Daten doch eh nur geladen werden sollen?
Delphi-Quellcode:
Type
  TVirtualQuery<T> = class
  private
    fTopIndex, fWindowSize : Integer;
    Procedure LoadWindow (page : Integer);
  public
    property Row[index : Integer] : T read GetRow; default;
  end;

...
Function TVirtualQuery<T>.GetRow (index : Integer) : T;
Begin
  Assert ((index>0) and (index < totalRows));

  if (index<fTopIndex) or (index>fTopIndex+fWindowSize-1) then
    LoadWindow(index div PageSize);

  result := fData[index - fTopIndex];
End;

Procedure TVirtualQuery<T>.LoadWindow (page : Integer);
Begin
  fData := LoadPageFromSQLServer (page, windowSize); // mit dem SQL-Befehl von Uwe
  fTopIndex := page*windowSize;
End;
Das ist die Logik. Den Rest kann man wuppdiwupp einfach selbst programmieren.

Wenn man ein wenig nachdenkt, braucht man kein 'totalrows', sondern läd einfach solange, bis der Server 'Error' meldet bzw. die Ergebnismenge leer ist. Ich weiss jetzt nicht genau, was der Server macht, wenn man eine Seite anfordert, die es gar nicht gibt...

himitsu 19. Jun 2014 21:06

AW: paged query im Eigenbau?
 
Der Vorteil, wenn es DBMS+Querykomponente das machen, daß dann die Daten konsistent bleiben, egal wie lange man drin rumscrollt, es bleibt immer in dem Zustand, wie zum Zeitpunkt der Abfrage.
Denn dort bleibt das Result-Set auf dem Server erhalten und das Query holt die Daten nur noch dort raus.

Bei den Aufteilen über einzelne Anfragen, könnte es ein Problem geben, wenn sich die Daten in der Tabelle zwischenzeitlich ändern.

Dejan Vu 19. Jun 2014 21:20

AW: paged query im Eigenbau?
 
Zitat:

Zitat von himitsu (Beitrag 1262948)
Der Vorteil, wenn es DBMS+Querykomponente das machen, daß dann die Daten konsistent bleiben, egal wie lange man drin rumscrollt, es bleibt immer in dem Zustand, wie zum Zeitpunkt der Abfrage.
Denn dort bleibt das Result-Set auf dem Server erhalten und das Query holt die Daten nur noch dort raus.

Und wie groß ist der Speicherverbrauch, wenn man einmal durchgescrollt hat und die Daten schön gecached sind und alle so, wie am Anfang?

Die Problematik hier liegt nicht am anschauen hübscher Terrabytes, sondern am skalierbaren durchlaufen einer sehr großen Datenmenge in akzeptabler Zeit. Da das lesen einzelner Datensätze einfach zu lange dauert, will der TE das happenweise machen. Dafür eignet sich nun mal das paging, denn das sind ja happen.

Mein Minipseudocode soll nur zeigen, wie man das hinter einer Art Liste verbergen kann. Man kann auch einfach einen Enumerator implementieren, dann kann man das komplett in einer for-in Schleife durchlaufen. Das wäre sogar noch richtigerer als mein kleines Dingsda, was ja eigentlich nur zeigen soll, wie simpel der ganze Kladderadatsch ist.

Sir Rufo 20. Jun 2014 03:48

AW: paged query im Eigenbau?
 
@himitsu

Das kommt einfach auf die Implementierung an.

Nehmen wir mal an, der erste Zugriff erstellt aus der Abfrage eine temporäre Tabelle (auf dem Server) und holt von dort dann die erste Seite. Alle anderen Seiten werden dann nur noch aus der temporären Tabelle geladen.

Eine andere Sortierung ist auch problemlos möglich (über die temporäre Tabelle).

Dejan Vu 20. Jun 2014 06:45

AW: paged query im Eigenbau?
 
Zitat:

Zitat von Sir Rufo (Beitrag 1262960)
... Nehmen wir mal an, der erste Zugriff erstellt aus der Abfrage eine temporäre Tabelle (auf dem Server) und holt von dort dann die erste Seite. ...

Leute, wir reden hier von 100 Mio Zeilen, die möglichst schnell durchlaufen werden sollen. Glaubt ihr ernsthaft, das eine andere Lösung als 'happenweise einlesen' besser oder auch nur im Ansatz brauchbar ist?.

Das Erstellen einer mehrere GiB großen temporären Tabelle dauert ewig, weil die Daten committed werden müssen und müllen den Server zu. Mach das ein paar mal (am Besten noch gleichzeitig) und egal wie viele TB Plattenplatz du hasthattest, nu sindse weg. Und das alles nur, weil ein Programmierer die grandiose Idee hatte, eine Tabelle zu klonen, nur um in Ruhe in ihr rumscrollen zu können. Sofern die Vorgabe 'während des Rumstöberns will ich Änderungen nicht sehen' ist, könnte man noch drüber nachdenken, wobei dann ein serverseitiger Cursor mit entsprechendem Isolation Level einfacher wäre (wenn der Cursor das mit macht), aber hinsichtlich der Speicherverplemperei ebenso suboptimal.

Wir wissen ja, das rumstöbern in 100 Mio Datensätzen eh Blödsinn ist und daher muss man sich über solche Ansätze keine Gedanken machen. Wenn ich meine Daten unverändert abholen will, erstelle ich einfach einen application lock auf der Tabelle, hole das Zeugs ab und fertig ist die Laube. Es wäre vielleicht auch *sinnvoll*, das zu sperren, denn sonst sind die Ergebnisse widersprüchlich ('Aber ich habe doch die Änderungen gespeichert? Wieso sieht man das in der Statistik nicht? In meiner sieht man das aber, und die wurde zur gleichen Zeit erstellt. Admin: Du bist gefeuert!')

himitsu 20. Jun 2014 07:04

AW: paged query im Eigenbau?
 
Das kommt auch auf die Daten drauf an.

z.B. egal ob du nun selber das aufteilst, oder ob das System es macht.
Dank deines
SQL-Code:
ORDER BY PrimaryKeyPreferablyWithAClusteredIndex
im Beispielcode muß die DB sowieso erstmal die komplette Result-Tabelle zusammenstellen, um sie überhaupt erstmal sortieren zu können und danach wird und kann erst der Ausschnitt extrahiert werden.
Wenn du das nun immer wieder neu abfragst, dann macht das die DB praktisch jedes mal von Neuem.
Und selbst ohne Sortierung werden viele DBMS das Result vermutlich dennoch umkopieren, denn sonst müsste sie die Tabelle vermutlich für andere Schreibzugriffe sperren, bis man endlich alles runtergeladen hat. Oder diese Zugriffe landen so lange, wie bei einer Transaktion, im Cache und werden erst in die Tabelle geschrieben, nachdem du mit Runterladen der aktuellen Anfrage fertig bis.

Wenn man nun wirklich nur die Daten von oben nach unten durchgehen will, dann ist es doch besser, wenn die DB das nur einmal machen muß und man dann das Result sich vom System stückchenweise nachladen lässt? :gruebel:

Dejan Vu 20. Jun 2014 07:10

AW: paged query im Eigenbau?
 
Zitat:

Zitat von himitsu (Beitrag 1262968)
Dank deines
SQL-Code:
ORDER BY PrimaryKeyPreferablyWithAClusteredIndex
im Beispielcode muß die DB sowieso erstmal die komplette Result-Tabelle zusammenstellen, um sie sortieren überhaupt zu können

Nein! Nicht bei einem Clustered Index (deswegen heißt die Spalte ja so). Das ist der Trick. Bei einem Clustered Index liegen die Daten bereits sortiert im B-Baum.

Das bedeutet, das Du derartig angelegte Tabellen wirklich ohne jegliche Verzögerung durchscrollen kannst. Bei anderen RDMBS geht das anders. Bei SQL-Server aber eben so.

himitsu 20. Jun 2014 07:16

AW: paged query im Eigenbau?
 
Gut, Sortieren ist auch möglich, wenn man immer nur Ausschnitte kennt, aber das ist dann auch ein klitzekleines bissl aufwändiger.
[edit] Hmmm, beim Einfügen jedes Datensatzes kann man ist es einfacher, da dort ja nur "alles" mit dem jeweiligen Satz verglichen werden muß.

Na dann :shock:
Dann ist der Aufwand wohl in die Indexerstellung verschoben und braucht beim Auslesen nicht mehr gemacht zu werden. :D

Dejan Vu 20. Jun 2014 10:11

AW: paged query im Eigenbau?
 
Vom Sortieren muss man sich verabschieden, wenn man mit riesigen Datenmengen zu tun hat. Das ist aber auch irrelevant, denn -zum 1000000sten mal- anschauen tut sich das keine Sau. Klar will man immer ein Grid haben, in dem alle Daten sichtbar sind und man *könnte* wenn man wollte durch die Zeilen durchscrollen und man kann sortieren und gruppieren und superallesmachen. Aber...

dafür gibt es OLAP.


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:14 Uhr.

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