2016-11-30 2 views
3

finde ich eine sehr einfache UNION-Abfrage, um gebaut habe den ‚Typen‘ einen UUID ging in meine Frage, wie so zu bestimmen:Kurzschluss UNION-Abfrage, wenn erstes Ergebnis

(
    SELECT 
    CASE WHEN id IS NOT NULL THEN 'player_id' ELSE '' END AS uuid_type 
    FROM db.players 
    WHERE id = $1 
) 
UNION 
(
    SELECT 
    CASE WHEN id IS NOT NULL THEN 'game_id' ELSE '' END AS uuid_type 
    FROM db.games 
    WHERE id = $1 
) 
UNION 
(
    SELECT 
    CASE WHEN id IS NOT NULL THEN 'location_id' ELSE '' END AS uuid_type 
    FROM db.locations 
    WHERE id = $1 
) 
UNION 
(
    SELECT 
    CASE WHEN id IS NOT NULL THEN 'promo_id' ELSE '' END AS uuid_type 
    FROM db.promos 
    WHERE id = $1 
) 

Gibt es eine Möglichkeit Diese Abfrage "kurzschließen", so dass sie stoppt, wenn ein Ergebnis gefunden wird. Beispiel: Wenn die erste Unterabfrage erfolgreich ist und uuid_type auf player_id festgelegt ist, möchte ich, dass die Abfrage beendet wird, da das Überprüfen der anderen drei Tabellen jetzt nicht mehr erforderlich ist.

+0

Ich denke, Sie können einen 'case' Ausdruck verwenden, um dies zu tun. –

+0

Nach meiner Erfahrung ist es besser, wenn Bezeichner einen Namespace enthalten; zum Beispiel könnten Sie 'player: c495a50a-b74c-11e6-80f5-76304dec7eb7' anstelle von' c495a50a-b74c-11e6-80f5-76304dec7eb7' haben. Wir betrachten Namespaces häufig nur als einen Weg, Namespace-Kollisionen zu verhindern (die Sie bereits durch die Verwendung von UUIDs verhindern), aber in der Praxis habe ich festgestellt, dass es oft sehr hilfreich für Ingenieure (Entwickler, QA, Support usw.) ist in der Lage sein, den Typ eines Bezeichners zu identifizieren, indem man ihn prüft, Protokolle untersucht, Probleme untersucht, usw. * [fortgesetzt] * – ruakh

+0

* [fortgesetzt] * Dies erleichtert Ihnen auch das Leben, wenn Sie einen Datentyp hinzufügen möchten das wird in einem anderen System gemeistert; Zum Beispiel möchten Sie vielleicht, dass die Abrechnung von einem separaten Microservice abgewickelt wird, der nicht mit dem Gameplay übereinstimmt. In diesem Fall möchten Sie wissen, welchen Microservice Sie anrufen müssen, um nach einer bestimmten Kennung zu suchen. – ruakh

Antwort

3

Wie wäre es mit einer Verschmelzung?

Select coalesce((Select 'player_id' from db.players where id = $1), 
       (Select 'game_id' from db.players where id = $1), 
       (Select 'location_id' from db.players where id = $1), 
       (Select 'promo_id' from db.players where id = $1)) 
+0

Ich denke, das wird funktionieren. 'coalesce()' ist gleichbedeutend mit einem 'case', der kurzschließt. –

4

Ich habe keine Postgres verfügbar, um es zu testen. Aber es soll wie folgt funktionieren:

SELECT t.uuid_type 
FROM (
    (
     SELECT 
     CASE WHEN id IS NOT NULL THEN 'player_id' ELSE '' END AS uuid_type 
     FROM db.players 
     WHERE id = $1 
    ) 
    UNION ALL 
    (
     SELECT 
     CASE WHEN id IS NOT NULL THEN 'game_id' ELSE '' END AS uuid_type 
     FROM db.games 
     WHERE id = $1 
    ) 
    UNION ALL 
    (
     SELECT 
     CASE WHEN id IS NOT NULL THEN 'location_id' ELSE '' END AS uuid_type 
     FROM db.locations 
     WHERE id = $1 
    ) 
    UNION ALL 
    (
     SELECT 
     CASE WHEN id IS NOT NULL THEN 'promo_id' ELSE '' END AS uuid_type 
     FROM db.promos 
     WHERE id = $1 
    ) 
) t LIMIT 1; 

LIMIT 1 begrenzt das Ergebnis auf eine einzige Zeile. Und indem Sie UNION durch ersetzen, sollte die Abfrage effizienter sein, und Dubletten müssen nicht mehr identifiziert und entfernt werden.

+0

Das schließt die Union wirklich nicht kurz, alle 4 Abfragen laufen noch. Zusätzlich Limit ohne Bestellung von? Sind wir sicher, dass die Gewerkschaftsergebnisse immer in der Reihenfolge der Ausführung zurückkommen würden? – xQbert

+0

@xQbert: Woher wissen Sie, dass alle vier Unterabfragen ausgeführt werden. Hast du eine Ausführungsstatistik, die das zeigt? Die LIMIT-Anweisung ist ein starker Hinweis darauf, dass der Optimierer keine Daten abfragt. Und meine Annahme ist, dass die ID-Spalten in den vier Tabellen disjunkt sind. Ansonsten macht die Abfrage keinen Sinn. – Codo

+3

@Codo: Es wird eine "UNION ALL" kurzgeschlossen, jedoch keine "UNION" (die alle Unterabfragen ausführt und Duplikate ausfiltert, bevor das Limit angewendet wird). Hier ist eine [Demo] (http://rextester.com/DXSG68122); Wie Sie sehen können, sagt der 'Seq scan on b'-Knoten der zweiten Abfrage" nie ausgeführt ". –