2016-10-06 6 views
0

Der Kontext ist eine Transaktionstabelle mit Datum und UserAccount. Diese Tabelle enthält ungefähr Milliarden Zeilen.Wie eine Zeile pro Schlüssel in linken äußeren Join erhalten

dOperationValueDate sUserAccount         
------------------- ---------------------------------------------- 
2016-03-05   00000000001         
2016-03-06   00000000002         
2016-03-07   00000000003         
2016-03-08   00000000004         
2016-03-09   00000000005         
2016-04-05   00000000002         
2016-10-05   00000000001         
2016-10-06   00000000001         
2016-10-06   00000000005         

Ich mag würde mit diesen Kriterien auf Daten in meiner Tabelle finden:

  • Mindestens eine Transaktion vor vor 6 Monaten (wie TOP 1 *)
  • Keine Transaktion für 6 Monate

In meinem Beispiel würde die Ergebnisse Konten 2, 3, 4 sein

ich mit gestartet ein LEFT OUTER JOIN, um alle userId mit Transaktion seit 6 Monaten zu entfernen. Aber die Bearbeitungszeit ist einfach schrecklich: für 4 Stunden gerade jetzt.

Ich denke, die Lösung besteht darin, nur eine Operation in der b-Abfrage zu finden, und sql stoppt, wenn eine Zeile gefunden wird. Das Hauptproblem ist nur, wenn der Benutzer vor 6 Monaten keine Transaktion hat, aber für die anderen wird es in Ordnung sein.

Auf der anderen Seite muss ich jede Transaktion seit 6 Monaten überprüfen, um Kunden aus dem Anwendungsbereich zu entfernen.

Ich las über Cross APPLY, aber ich bin mir nicht sicher, wie es funktioniert.

Das Hauptproblem ist hier die Bearbeitungszeit. Ich muss eine "schnelle" Anfrage (weniger als 1 Stunde) machen.

+1

Hier ist ein großartiger Ort, um zu beginnen. http://spaghettidba.com/2015/04/24/how-to-post-at-sql-question-on-a-public-forum/ –

+0

Haben Sie zufällig einen einzigen Index aus 'sUserAccount' und' dOperationValueDate' (in dieser Reihenfolge)? (Sind diese faux-ungarische Notation Spalte Namen?) – HABO

Antwort

0

Ich denke, Sie sollten einfach NOT EXISTS hier verwenden können.

SELECT b.sUserAccount 
FROM T_Operations b WITH (READUNCOMMITTED) 
WHERE b.dOperationValueDate < DATEADD(month,-6,DATEADD(month,DATEDIFF(month,0,GETUTCDATE()),0)) 
     AND NOT EXISTS (SELECT 1 
         FROM T_Operations WITH (READUNCOMMITTED) 
         WHERE sUserAccount = b.sUserAccount 
           AND dOperationValueDate >= DATEADD(month,-6,DATEADD(month,DATEDIFF(month,0,GETUTCDATE()),0))) 
GROUP BY b.sUserAccount -- all operations before 6 months ago 

oder tatsächlich, können Sie möglicherweise nur mit GROUP BY verwenden

SELECT sUserAccount 
FROM T_Operations WITH (READUNCOMMITTED) 
GROUP BY sUserAccount 
HAVING MAX(dOperationValueDate) < DATEADD(month,-6,DATEADD(month,DATEDIFF(month,0,GETUTCDATE()),0)) 

als eine Randnotiz, DIE .. DATEADD(month,-6,DATEADD(month,DATEDIFF(month,0,GETUTCDATE()),0))2016-04-01

zurückkehren würde, wenn Sie das aktuelle Datum wollen, minus sechs Monate, die Sie verwenden können DATEADD(month,-6,CAST(GETUTCDATE() AS DATE)) oder DATEADD(month,-6,DATEADD(day,DATEDIFF(day,0,GETUTCDATE()),0)

+0

@BaptX die zweite Option, die HAVING – JamieD77

+0

Ich mag die zweite Option. Ich werde ein paar Perf-Tests machen. – BaptX

+0

Ihre zweite Methode dauert nur 3 Minuten, während Paparazzi-Methode dauert 4 Minuten, während meine dauert ... 89 Minuten: O – BaptX

0
datatime @dt = DATEADD(month, -6, DATEADD(month, DATEDIFF(month, 0, GETUTCDATE()), 0)); 
SELECT sUserAccount 
FROM T_Operations WITH (readuncommitted) 
WHERE dOperationValueDate < @dt 
EXCEPT 
SELECT sUserAccount 
FROM T_Operations WITH (readuncommitted) 
WHERE dOperationValueDate >= @dt; 

Haben Sie einen Index auf dOperationValueDate

Verwandte Themen