2016-07-25 50 views
1

我有此視圖vMobileHistory_MobileRegion其是這樣的:SQL服務器:分組列的連續值

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 

索引是:

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

我已經基於連續值這個查詢是到組行「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 

的問題是,vMobileHistory_MobileRegion擁有超過行的100M和使用ROW_NUMBER()導致所有行的計算結果爲ROW_NUMBER(),這些行非常慢,並且由於大量數據不適合內存,導致在tempdb中排序數據。

有沒有其他方式沒有使用ROW_NUMBER()

其實,我需要時間持續時間isValidRegion

+0

你想用row_number函數來計算什麼? –

+0

這是計算兩個不同分區的RowNumber的差異以確定「isValidRegion」是否連續。 –

+0

您是否有任何索引?這不是'ROW_NUMBER()'導致的主要性能問題,排序100M記錄速度很慢。 –

回答

0

的每個連續的值,我不能完全再現您的環境,但這裏是我做過什麼(概念):

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) 

下面是最終查詢,分裂到的CTE看到的解決方案部分:

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 

這需要引起最終GROUP BY只有一個排序操作。下面的結果:

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 

如果沒有指定結束時間,我用0.1 TOTALTIME是在幾秒鐘內,您的查詢可能進行調整使用一些不同的方法來計算,由於strDate和strTime列的時間跨度。

+0

這是完美的Pawel,我非常喜歡這種思維方式,但是這是在考慮40秒也返回結果(與我的查詢相同)。我; m使用此查詢主要是爲特定的日期(其中strDate = XXXX)。這大約需要40秒才能返回結果。但是,如果我過濾更多,如(其中strDate = XXX和strTIme> '12:00'),這將需要不到1秒! 與執行計劃的唯一區別是,排序不會再傳遞給tempdb,也許我必須對服務器內存做些什麼 –

+0

您的/我的執行計劃中有多少個排序操作?它只有1?該表與服務器內存有多大? –

+0

你有1排序,這是完美的(我的查詢有2種)。但我認爲這些排序已經完成了,因爲索引。我會發布你的查詢和我的實際執行計劃。 –