Анализировать данные на основе времени и получать распределение данных в SQL Server - PullRequest
0 голосов
/ 05 сентября 2011

Я хотел бы проанализировать исторические данные, чтобы получить распределение данных.

Данные из таблицы tData основаны на 15 минутах и ​​содержат более 10 миллиардов записей, что делает производительность действительно важной. Я хотел бы проанализировать все 96 баллов (1 день = 96 * 15 минут) за все годы данных.

Например, для «00:15» я получу минимум и максимум по всем данным, которые «00:15», скажем:

2010-01-01 00:15
2010-01-02 00:15
2010-01-03 00:15
2010-01-04 00:15
2010-01-05 00:15
2010-01-06 00:15
2010-01-07 00:15
...
...

Затем я буду использовать следующий запрос, чтобы получить распределение данных в 10 разделах из таблицы tData (DeviceID + FooTime - это PK), а tData - это физическая таблица, но здесь только для тестового примера:

declare @tData table(DeviceID nvarchar(10), FooTime datetime, Value float)

--just dummy data, actual data will have full 96 points for each day
INSERT INTO @tData VALUES ('PM00100', '2010-01-01 00:15', 3)
INSERT INTO @tData VALUES ('PM00100', '2010-01-02 00:15', 4)
INSERT INTO @tData VALUES ('PM00100', '2010-01-03 00:15', 5)
INSERT INTO @tData VALUES ('PM00100', '2010-01-04 00:15', 2)
INSERT INTO @tData VALUES ('PM00100', '2010-01-05 00:15', 3)
INSERT INTO @tData VALUES ('PM00100', '2010-01-06 00:15', 4)
INSERT INTO @tData VALUES ('PM00100', '2010-01-07 00:15', 5)
INSERT INTO @tData VALUES ('PM00100', '2010-01-08 00:15', 6)
INSERT INTO @tData VALUES ('PM00100', '2010-01-09 00:15', 7)
INSERT INTO @tData VALUES ('PM00100', '2010-01-10 00:15', 11)
INSERT INTO @tData VALUES ('PM00100', '2010-01-11 00:15', 12)
INSERT INTO @tData VALUES ('PM00100', '2010-01-12 00:15', 13)
INSERT INTO @tData VALUES ('PM00100', '2010-01-13 00:15', 14)
INSERT INTO @tData VALUES ('PM00100', '2010-01-14 00:15', 15)
INSERT INTO @tData VALUES ('PM00100', '2010-01-15 00:15', 16)
INSERT INTO @tData VALUES ('PM00100', '2010-01-16 00:15', 17)
INSERT INTO @tData VALUES ('PM00100', '2010-01-17 00:15', 18)
INSERT INTO @tData VALUES ('PM00100', '2010-01-18 00:15', 10)
INSERT INTO @tData VALUES ('PM00100', '2010-01-19 00:15', 19)
INSERT INTO @tData VALUES ('PM00100', '2010-01-20 00:15', 9)
INSERT INTO @tData VALUES ('PM00100', '2010-01-21 00:15', 8)
INSERT INTO @tData VALUES ('PM00100', '2010-01-22 00:15', 3)
INSERT INTO @tData VALUES ('PM00100', '2010-01-23 00:15', 4)
INSERT INTO @tData VALUES ('PM00100', '2010-01-24 00:15', 4)
INSERT INTO @tData VALUES ('PM00100', '2010-01-25 00:15', 2)
INSERT INTO @tData VALUES ('PM00100', '2010-01-26 00:15', 2)
INSERT INTO @tData VALUES ('PM00100', '2010-01-27 00:15', 5)
INSERT INTO @tData VALUES ('PM00100', '2010-01-28 00:15', 6)
INSERT INTO @tData VALUES ('PM00100', '2010-01-29 00:15', 2)
INSERT INTO @tData VALUES ('PM00100', '2010-01-30 00:15', 14)
INSERT INTO @tData VALUES ('PM00100', '2010-01-31 00:15', 15)
INSERT INTO @tData VALUES ('PM00100', '2010-02-01 00:15', 25)

DECLARE @CurrentPoint nvarchar(10) 
DECLARE @MinValue float 
DECLARE @MaxValue float 
DECLARE @AvgValue float 
DECLARE @StartDate datetime 
DECLARE @EndDate datetime 
DECLARE @RangeWidth float 
DECLARE @RangeCount float 

SET @StartDate = '2010-01-01' 
SET @EndDate = '2010-02-02' 
SET @CurrentPoint = '00:15' 
SET @RangeCount = 9 

SELECT @MinValue = MIN(Value), @MaxValue = MAX(Value), @AvgValue = AVG(Value) 
    FROM @tData  
    WHERE DeviceID = 'PM00100' AND FooTime between @StartDate and @EndDate AND CONVERT(nvarchar(5), FooTime, 108) = @CurrentPoint 

SET @RangeWidth = (@MaxValue - @MinValue) / @RangeCount 

SELECT FLOOR((Value - @MinValue)/@RangeWidth) * @RangeWidth + @MinValue as LowerBound 
    ,FLOOR((Value - @MinValue)/@RangeWidth) * @RangeWidth + @MinValue + @RangeWidth as UpperBound 
    ,COUNT(*) AS Count 
    ,FLOOR((Value - @MinValue)/@RangeWidth) AS Position 
    FROM @tData  
    WHERE DeviceID = 'PM00100' AND FooTime between @StartDate and @EndDate AND CONVERT(nvarchar(5), FooTime, 108) = @CurrentPoint 
    GROUP BY FLOOR((Value - @MinValue) / @RangeWidth) 

Вышеупомянутый запрос получает разницу между максимальным и минимальным значениями и делит на 9 (получается 10 секций) для каждого диапазона данных, который я хотел бы получить, сколько записей принадлежит этому диапазону. Позиция просто выводит индекс.

Запрос отлично работает для одной 15-минутной точки данных, но когда я хочу выполнить все 96 точек (ежедневно, с 00:00 до 23:45), сейчас я использую цикл, он очень медленный. Я считаю, что это потому, что мне не нужно делать 96 запросов, я мог сделать это за один раз, но я не мог понять это.

результат будет выглядеть так:

LowerBound       UpperBound         Count Position
2.00000000000000 4.55555555555556   11    0
4.55555555555556 7.11111111111111   6     1
7.11111111111111 9.66666666666667   2     2
9.66666666666667 12.2222222222222   3     3
12.2222222222222 14.7777777777778   3     4
14.7777777777778 17.3333333333333   4     5
17.3333333333333 19.8888888888889   2     6
25.0000000000000 27.5555555555556   1     9

Ответы [ 2 ]

1 голос
/ 05 сентября 2011

Я не совсем уверен, что следую другим расчетам, зачем сначала нужно использовать AVG / MAX и т. Д., Что означают RangeCount и RangeWidth и т. Д., Но, возможно, это даст вам начало:

;WITH cte(t,v) AS 
(
    SELECT CONVERT(CHAR(5), FooTime, 108), [Value]
      FROM @tData
      WHERE FooTime BETWEEN @StartDate AND @EndDate
)
SELECT t,MIN(v),MAX(v),AVG(v) FROM cte GROUP BY t;

Это даст вам строку для каждого отрезка времени. Вы можете вложить больше CTE для дальнейших вычислений с агрегатами. Я не мог сделать начальные и конечные результаты вычислений, которые вы делали, и казалось, что ваши данные выборки и желаемые результаты не совсем совпадают.

0 голосов
/ 06 сентября 2011

Я нашел способ повысить производительность, выполняя запрос за один раз, а не итерируя все временные точки.Сначала мин / макс для каждой точки и сохраните их во временной таблице.

CREATE TABLE #ProfiledData(ID int identity(1,1), TimePoint nchar(5), MinValue float NULL, MaxValue float NULL, RangeWidth float NULL)
DECLARE @RangeCount float   
SET @RangeCount = 9
declare @tData table(DeviceID nvarchar(10), FooTime datetime, Value float)
--just dummy data, actual data will have full 96 points for each day  
INSERT INTO @tData VALUES ('PM00100', '2010-01-01 00:00', 3)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-02 00:00', 4)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-03 00:00', 5)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-04 00:00', 2)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-05 00:00', 3)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-06 00:00', 4)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-07 00:00', 5)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-08 00:00', 6)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-09 00:00', 7)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-10 00:00', 11)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-11 00:00', 12)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-12 00:00', 13)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-13 00:00', 14)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-14 00:00', 15)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-15 00:00', 16)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-16 00:00', 17)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-17 00:00', 18)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-18 00:00', 10)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-19 00:00', 19)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-20 00:00', 9)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-21 00:00', 8)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-22 00:00', 3)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-23 00:00', 4)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-24 00:00', 4)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-25 00:00', 2)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-26 00:00', 2)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-27 00:00', 5)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-28 00:00', 6)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-29 00:00', 2)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-30 00:00', 14)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-31 00:00', 15)  
INSERT INTO @tData VALUES ('PM00100', '2010-02-01 00:00', 25)  

INSERT INTO @tData VALUES ('PM00100', '2010-01-01 00:15', 3)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-02 00:15', 4)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-03 00:15', 5)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-04 00:15', 2)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-05 00:15', 3)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-06 00:15', 4)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-07 00:15', 5)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-08 00:15', 6)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-09 00:15', 7)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-10 00:15', 11)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-11 00:15', 12)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-12 00:15', 13)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-13 00:15', 14)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-14 00:15', 15)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-15 00:15', 16)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-16 00:15', 17)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-17 00:15', 18)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-18 00:15', 10)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-19 00:15', 19)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-20 00:15', 9)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-21 00:15', 8)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-22 00:15', 3)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-23 00:15', 4)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-24 00:15', 4)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-25 00:15', 2)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-26 00:15', 2)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-27 00:15', 5)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-28 00:15', 6)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-29 00:15', 2)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-30 00:15', 14)  
INSERT INTO @tData VALUES ('PM00100', '2010-01-31 00:15', 15)  
INSERT INTO @tData VALUES ('PM00100', '2010-02-01 00:15', 25)  

INSERT INTO #ProfiledData (TimePoint) VALUES ('00:00')
INSERT INTO #ProfiledData (TimePoint) VALUES ('00:15')
--...
--...

UPDATE #ProfiledData SET MinValue = m.MinValue, MaxValue = m.MaxValue, RangeWidth = (m.MaxValue - m.MinValue) / @RangeCount
    FROM (SELECT CONVERT(nchar(5), FooTime, 108) AS TimePoint, MIN(Value) AS MinValue, MAX(Value) AS MaxValue
        FROM @tData
        GROUP BY CONVERT(nchar(5), FooTime, 108)) m
    LEFT JOIN #ProfiledData a ON a.TimePoint = m.TimePoint

SELECT a.TimePoint
    ,FLOOR((Value - MinValue)/ RangeWidth) * RangeWidth + MinValue as LowerBound
    ,FLOOR((Value - MinValue)/ RangeWidth) * RangeWidth + RangeWidth + MinValue as UpperBound
    ,COUNT(*) AS Total
    ,FLOOR((Value - MinValue)/ RangeWidth) AS Position
    FROM @tData d
        INNER JOIN #ProfiledData a ON a.TimePoint = CONVERT(nchar(5), d.FooTime, 108)
    WHERE d.DeviceID = 'PM00100'
    GROUP BY a.TimePoint, RangeWidth, MinValue, FLOOR((Value - MinValue) / RangeWidth)

DROP TABLE #ProfiledData
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...