Субсэмплирование хранимых в SQL данных для графиков - PullRequest
1 голос
/ 20 января 2011

Предположим, у вас есть программа, которая регистрирует (timestamp, stock_price) в базе данных SQL каждые 30 секунд, и вы хотите сгенерировать графики цены акций за различные периоды времени.Если вы строите измерения в диапазоне 1 часа, то можно использовать все 120 образцов, взятых за это время.Однако, если вы хотите построить график цен за 1 год, вы, очевидно, не хотите извлекать более 1 миллиона образцов из базы данных.Было бы лучше вытащить некоторое репрезентативное подмножество выборок из базы данных.

Это напоминает мне технику уровня детализации в компьютерной графике - по мере того, как вы удаляетесь от 3d-модели, снижается точностьможно использовать версию модели.

Существуют ли распространенные методы для представления информации об уровне детализации в базе данных или для быстрого запроса равномерно разнесенного подмножества данных (например, дайте мне 100 равномерно разнесенных выборок с января 2009 г.)?


Решение, которое я до сих пор придумал, состоит в том, чтобы включить столбец level_of_detail в таблицу базы данных.Если level_of_detail = 0, строка содержит одну мгновенную выборку.Если level_of_detail = n, строка содержит среднее значение последних (sample_interval * (2 ^ n)) секунд данных, и на этом уровне имеется 1 / (2 ^ n) столько строк.Таблица имеет индекс (level_of_detail, timestamp), и, когда вы хотите сгенерировать график, вы вычисляете соответствующее значение level_of_detail на основе требуемого количества выборок и запрашиваете это ограничение.Недостатки:

  • Для N выборок таблица должна хранить 2 * N строк
  • Клиент должен знать, чтобы указать соответствующее ограничение level_of_detail
  • Для некоторых процессов требуетсяотвечать за построение усредненных строк при добавлении выборок в таблицу

1 Ответ

2 голосов
/ 20 января 2011

Для SQL Server вы можете использовать ntile.Это упорядочивает набор данных, а затем разделяет его на N различных групп, возвращая 1 для первой группы и N для последней группы.

select  MIN(MeasureTime) as PeriodStart
,       MAX(MeasureTime) as PeriodEnd
,       AVG(StockPrice) as AvgStockPrice
from    (
        select  MeasureTime
        ,       StockPrice
        ,       NTILE(100) over (order by MeasureTime) as the_tile
        from    @t YourTable
        ) tiled
group by
        the_tile

Это вернет ровно 100 строк.Вот копия тестовых данных, если вы хотите попробовать запрос:

declare @t table (MeasureTime datetime, StockPrice int)
declare @dt date
set @dt = '2010-01-01'
while @dt < '2011-01-01'
    begin
    insert @t values (@dt, DATEDIFF(day,'2010-01-01',@dt))
    select @dt = DATEADD(day,1,@dt)
    end
...