2016-09-29 2 views
0

Problem zu finden: Hier finden Sie die aktuellsten Datensatz basierend auf (erstellt) Spalte für jede (linked_id) Spalt in mehreren Tabellen, sollen die Ergebnisse umfassen (user_id, MAX (erstellt), linked_id). Die Abfrage muss auch in der Lage sein, mit einer WHERE-Klausel verwendet zu werden, um einen einzelnen Datensatz basierend auf der (linked_id) zu finden.Abfrage optimiert, wenn sie versuchen letzten Datensatz in mehreren Tabellen für bestimmte Spalte

Es gibt tatsächlich mehrere Tabellen in Frage, aber hier sind 3 Tabellen, so dass Sie die Idee der Struktur bekommen können (es gibt mehrere andere Spalten in jeder Tabelle, die weggelassen wurden, da sie nicht zurückgegeben werden sollen).

CREATE TABLE em._logs_adjustments 
(
    id serial NOT NULL, 
    user_id integer, 
    created timestamp with time zone NOT NULL DEFAULT now(), 
    linked_id integer, 
    CONSTRAINT _logs_adjustments_pkey PRIMARY KEY (id) 
) 
WITH (
    OIDS=FALSE 
); 

CREATE TABLE em._logs_assets 
(
    id serial NOT NULL, 
    user_id integer, 
    created timestamp with time zone NOT NULL DEFAULT now(), 
    linked_id integer, 
    CONSTRAINT _logs_assets_pkey PRIMARY KEY (id) 
) 
WITH (
    OIDS=FALSE 
); 
CREATE TABLE em._logs_condition_assessments 
(
    id serial NOT NULL, 
    user_id integer, 
    created timestamp with time zone NOT NULL DEFAULT now(), 
    linked_id integer, 
    CONSTRAINT _logs_condition_assessments_pkey PRIMARY KEY (id) 
) 
WITH (
    OIDS=FALSE 
); 

Die Abfrage i mit einem kleinen Hack bin derzeit um die Notwendigkeit für user_id in den GROUP BY-Klausel zu erhalten, wenn möglich array_agg entfernt werden soll.

SELECT MAX(MaxDate), linked_id, (array_agg(user_id ORDER BY MaxDate DESC))[1] AS user_id FROM (
    SELECT user_id, MAX(created) as MaxDate, asset_id AS linked_id FROM _logs_assets 
    GROUP BY asset_id, user_id 
    UNION ALL 
    SELECT user_id, MAX(created) as MaxDate, linked_id FROM _logs_adjustments 
    GROUP BY linked_id, user_id 
    UNION ALL 
    SELECT user_id, MAX(created) as MaxDate, linked_id FROM _logs_condition_assessments 
    GROUP BY linked_id, user_id 
    ) as subQuery 
    GROUP BY linked_id 
    ORDER BY linked_id DESC 

I erhalten die gewünschten Ergebnisse, aber glaube nicht, dass das ist Recht Weg, dies zu tun, vor allem, wenn array_agg benutzt wird und soll nicht und einige Tische können nach oben von 1.5+ Millionen Datensätze Das Ausführen der Abfrage dauert mehr als 10 bis 15 Sekunden. Jede Hilfe/Steuerung in die richtige Richtung wird sehr geschätzt.

Antwort

1

distinct on

DISTINCT ON SELECT (expression [...]) hält nur die erste Zeile eines jeden Satzes von Zeilen, in denen die angegebenen Ausdrücke gleich zu bewerten. Die DISTINCT ON-Ausdrücke werden mit den gleichen Regeln wie für ORDER BY interpretiert (siehe oben). Beachten Sie, dass die „erste Reihe“ jeden Satz unberechenbar ist, es sei denn wird ORDER BY verwendet, um sicherzustellen, dass die gewünschte Zeile erste

select distinct on (linked_id) created, linked_id, user_id 
from (
    select user_id, created, asset_id as linked_id 
    from _logs_assets 
    union all 
    select user_id, created, linked_id 
    from _logs_adjustments 
    union all 
    select user_id, created, linked_id 
    from _logs_condition_assessments 
) s 
order by linked_id desc, created desc 
+0

Danke für die Hilfe Clo erscheint, aber auf der Suche die Abfrage zurückgeben, die max haben (erstellt) für jede linked_id. – Spade

+1

@Spade Genau das ist es. –

+0

Meine Schuld, es funktioniert wie erwartet (danke!), Aber die Ausführungszeit ändert sich nicht viel, es ist auf gleicher Ebene wie die Abfrage, die jetzt verwendet wird. – Spade

Verwandte Themen