2016-07-25 17 views
1

Ich habe diese Ansicht vMobileHistory_MobileRegion das ist wie:SQL Server: Gruppieren kontinuierlichen Wert einer Spalte

strUnitID  strDate  strTime iMobileHistory isValidRegion 
--------------------------------------------------------------- 
352848028160311 1394/11/01 10:35:16 33029937  0 
352848028160311 1394/11/01 10:35:17 33029938  0 
352848028160311 1394/11/01 10:35:18 33029939  1 
352848028160311 1394/11/01 10:35:19 33029940  1 
352848028160311 1394/11/01 10:35:20 33029941  1 
352848028160311 1394/11/01 10:35:22 33029942  0 
352848028160311 1394/11/01 10:35:25 33029943  0 
352848028160311 1394/11/01 10:35:28 33029944  0 
352848028160311 1394/11/01 10:35:34 33029945  1 
352848028160311 1394/11/01 10:35:35 33029946  1 

Indizes sind:

ClusterdIndex, strUnitID ASC, strDate DESC, strTime DESC 
NonClusterdIndex, iMobileHistory ASC 
NonClusterdIndex, strDate ASC, strTime ASC 
NonClusterdIndex, strUnitID ASC, strDate ASC 

Ich habe diese Abfrage, die kontinuierliche Werte zu Gruppenzeilen basiert "isValidRegion"

SELECT 
    strUnitID, 
    strDate, 
    strTime, 
    isValidRegion, 
    iMobileHistory, 
    (ROW_NUMBER() OVER (PARTITION BY strUnitId ORDER BY strDate, strTime) 
    - 
    ROW_NUMBER() OVER (PARTITION BY strUnitId, isValidRegion ORDER BY strDate, strTime) 
    ) AS grp 
FROM 
    vMobileHistory_MobileRegion 
GROUP BY 
    strUnitID, strDate, isValidRegion, grp 

Das Problem ist, dass vMobileHistory_MobileRegion über 100M von Zeilen hat und mit ROW_NUMBER() darauf verursacht Berechnung ROW_NUMBER() für alle Zeilen, die wirklich langsam ist und verursacht Sortierung Daten in tempdb wegen der großen Daten, die nicht in den Speicher passen.

Gibt es einen anderen Weg ohne ROW_NUMBER() zu verwenden?

Eigentlich, ich brauche Zeitdauer für jeden kontinuierlichen Wert von isValidRegion

+0

Was möchten Sie mit der Funktion rows_number berechnen? –

+0

Dies ist die Differenz von RowNumber für zwei verschiedene Partitionierung zu berechnen, um zu wissen, ob "isValidRegion" kontinuierlich ist oder nicht –

+0

Haben Sie irgendwelche Index (e)? Es ist nicht 'ROW_NUMBER()', was zu Hauptleistungsproblemen führt, das Sortieren von 100M-Datensätzen ist langsam. –

Antwort

0

kann ich nicht ganz Ihrer Umgebung reproduzieren, aber hier ist das, was ich (gedanklich) tat:

CREATE TABLE Regions 
(
    UnitID char(15), 
    EventTime datetime2, 
    MobileHistory int, 
    IsValidRegion bit 
) 

--Notice EventTime is not DESC, compacted to one column 
CREATE CLUSTERED INDEX IX_MobileHistory ON Regions(UnitId, EventTime) 

--You can join columns strDate and strTime in CTE expression 
--I omited this for simiplicity 
TRUNCATE TABLE Regions 
INSERT Regions VALUES 
('352848028160311', '1394/11/01 10:35:16', 33029937, 0), 
('352848028160311', '1394/11/01 10:35:17', 33029938, 0), 
('352848028160311', '1394/11/01 10:35:18', 33029939, 1), 
('352848028160311', '1394/11/01 10:35:19', 33029940, 1), 
('352848028160311', '1394/11/01 10:35:20', 33029941, 1), 
('352848028160311', '1394/11/01 10:35:22', 33029942, 0), 
('352848028160311', '1394/11/01 10:35:25', 33029943, 0), 
('352848028160311', '1394/11/01 10:35:28', 33029944, 0), 
('352848028160311', '1394/11/01 10:35:34', 33029945, 1), 
('352848028160311', '1394/11/01 10:35:35', 33029946, 1) 

Hier ist der letzte ist Abfrage, um CTEs gespaltet Teile der Lösung zu sehen:

WITH Lagged AS 
(
    SELECT CASE WHEN LAG(IsValidRegion) OVER (PARTITION BY UnitId ORDER BY EventTime) <> IsValidRegion THEN 1 ELSE 0 END IsChange, 
     ISNULL(DATEDIFF(second, EventTime, LEAD(EventTime) OVER (PARTITION BY UnitId ORDER BY EventTime)), 0) TimeSpan, 
     IsValidRegion*1 IsValidRegion, MobileHistory, UnitId, EventTime 
    FROM Regions 
), 
LaggedGroupChanges AS 
(
    SELECT *, SUM(CASE WHEN IsChange=1 THEN 1 ELSE 0 END) OVER (PARTITION BY UnitId ORDER BY EventTime) ChangeGroup 
    FROM Lagged 
) 
SELECT UnitId, SUM(TimeSpan) TotalTime, 
    MAX(IsValidRegion) IsValidRegion, 
    MIN(MobileHistory) MinMobileHistory, 
    MAX(MobileHistory) MaxMobileHistory 
FROM LaggedGroupChanges 
GROUP BY UnitId, ChangeGroup 

Es erfordert nur ein Sortiervorgang durch abschließendes GROUP BY verursacht. Die Ergebnisse unter:

UnitIdTotalTime TotalTime IsValidRegion MinMobileHistory MaxMobileHistory 
352848028160311 2   0    33029937   33029938 
352848028160311 4   1    33029939   33029941 
352848028160311 12  0    33029942   33029944 
352848028160311 1   1    33029945   33029946 

Wenn keine Endzeit angegeben ist, verwendet I 0 Totaltime in Sekunden ist, Ihre Abfrage einige verschiedene Methoden optimiert werden kann verwenden Zeitspannen aufgrund strDate und strTime Spalten zu berechnen.

+0

Das ist perfekt Pawel, ich mochte diese Art zu denken wirklich, aber das dauert ungefähr 40 Sekunden, um das Ergebnis zurückzugeben (wie meine Anfrage). Ich verwende diese Abfrage hauptsächlich für ein bestimmtes Datum (wobei strDate = XXXX). Dies dauert ungefähr 40 Sekunden, um das Ergebnis zurückzugeben. Aber wenn ich mehr filtere, wie (wo strDate = XXX und strTIme> '12: 00'), dauert das weniger als 1 Sekunden! und der einzige Unterschied zu Ausführungsplan ist, dass Sortierungen nicht mehr zu Tempdb verschüttet werden, vielleicht muss ich etwas über Server-Speicher tun –

+0

Wie viele Sortiervorgänge sind in Ihrem/meinem Ausführungsplan? Ist es nur 1? Wie groß ist dieser Tabellen- und Serverspeicher? –

+0

Ihre hat 1 Sorte und das ist perfekt (meine Abfrage hat 2 Sorten). Aber ich denke, diese Arten sind schon wegen der Indizes gemacht. Ich werde den tatsächlichen Ausführungsplan Ihrer Anfrage und meines veröffentlichen. –