2016-10-27 7 views
0

Betrachten wir aus Dutzenden von Tabellen mit unterschiedlicher Struktur komplexe union select haben aber ähnliche Feldern Bedeutung:Conditional auf Union Offset wählen

SELECT a1.abc as field1, 
     a1.bcd as field2, 
     a1.date as order_date, 
FROM a1_table a1 
UNION ALL 
SELECT a2.def as field1, 
     a2.fff as field2, 
     a2.ts as order_date, 

FROM a2_table a2 
UNION ALL ... 

ORDER BY order_date 

Beachten Sie auch, dass die Ergebnisse im Allgemeinen order_date durch „synthetisches“ Feld sortiert.

Diese Abfrage gibt eine große Anzahl von Zeilen, und wir möchten mit Seiten aus dieser Reihe von Zeilen arbeiten. Jede Seite wird durch zwei Parameter definiert:

  • Seitengröße
  • field2 Wert des letzten Element aus der vorherigen Seite

Wichtigste, dass können wir nicht die Art und Weise ändern Seite definiert. I.e. Es ist nicht möglich, die Zeilennummer des Datums des letzten Elements von der vorherigen Seite zu verwenden: Nur field2 Wert ist akzeptabel.

Aktuelle Algorithmus von Paging in ziemlich hässlich Weise umgesetzt wird:

1) Abfrage oben in zusätzlichen wählen mit row_number() zusätzlichen Spalt gewickelt und dann in Stored Procedure union_wrapper gewickelt, die table (field1 ..., field2 character varying) entsprechende zurückkehrt,

2) dann komplexe Auswahl ausgeführt:

Das Problem ist, dass wir Speicher voll Union-Select erstellen müssen Ergebnisse, um später die Zeilennummer zu ermitteln, von der wir eine neue Seite ausschneiden möchten. Dies ist ziemlich langsam und dauert unannehmbar viel Zeit.

Gibt es eine Möglichkeit, diese Vorgänge neu zu konfigurieren, um die Komplexität der Abfragen erheblich zu reduzieren und ihre Geschwindigkeit zu erhöhen?

Und noch einmal: Wir können den Zustand des Paging nicht ändern, wir können die Struktur der Tabellen nicht ändern. Einzige Möglichkeit zum Abrufen von Zeilen.

UPD: Ich kann auch nicht temporäre Tabellen verwenden, weil ich in Read-Replica der Datenbank arbeite.

+0

'ORDER BY order_date' <--> WHERE field2 = last_field_id' ich ein Highwatermark erwarten würde zumindest der führende Teil des Bestell/Index sein. Und da Ihr Datenmodell verkrüppelt ist, könnten Sie eine temporäre Tabelle oder eine marterialisierte Ansicht berücksichtigen. – joop

+0

@joop Ich kann keine temporären Tabellen verwenden, da ich in Read-Replica arbeite. Entschuldigung, ich habe das in meiner Frage nicht erwähnt, also werde ich es aktualisieren – Andremoniy

+0

Wenn Sie all diese "UNION ALL" trotzdem verwenden müssen, glaube ich, dass row_number over() 'nicht so hässlich ist für Paginierung –

Antwort

0

Sie haben sich erfolgreich in eine Engstelle manövriert. Die Abfrage und ihre ORDER BY Expression widersprechen Ihren Paging-Anforderungen.

ORDER BY order_date ist kein determinis Sortierreihenfolge (es mehrere Zeilen mit demselben order_date sein könnte) - die Sie Notwendigkeit, bevor Sie etwas anderes tun hier. Und field2 scheint auch nicht einzigartig zu sein. Sie benötigen beide: Definieren Sie eine deterministische Sortierreihenfolge und einen eindeutigen Indikator für das Ende/Starten der Seite. Im Idealfall entspricht der Indikator der Sortierreihenfolge. Könnte (order_date, field2) sein, die beide Spalten definiert NOT NULL, und die Kombination UNIQUE. Ihre Einschränkung "only field2 value is acceptable" widerspricht Ihrer Abfrage.

Das ist alles vor ist darüber nachzudenken, wie die beste Leistung zu erhalten ...

Es sind bewährte Lösungen mit Zeilenwerte und Indizes mit mehreren Spalten für Paging:

Aber das Zeichnen aus einer Kombination mehrerer Quellentabellen erschwert die Sache. Die Optimierung hängt von den Details Ihrer Einrichtung ab.

Wenn Sie nicht die Leistung erhalten, die Sie benötigen, ist Ihre einzige verbleibende Alternative, die Abfrageergebnisse irgendwie zu materialisieren. Temp-Tabelle, Cursor, materialisierte Ansicht - das beste Werkzeug hängt von den Details Ihrer Einrichtung ab.

Of course, general performance tuning might help, too.