【问题标题】:Make statistics out of a SQL table [closed]从 SQL 表中进行统计[关闭]
【发布时间】:2018-02-13 03:29:11
【问题描述】:

我的数据库中有一个表格,我可以通过这种方式记录来自多个传感器的读数:

CREATE TABLE [test].[readings] (
    [timestamp_utc] DATETIME2(0) NOT NULL, -- 48bits
    [sensor_id] INT NOT NULL, -- 32 bits
    [site_id] INT NOT NULL, -- 32 bits
    [reading] REAL NOT NULL, -- 64 bits
    PRIMARY KEY([timestamp_utc], [sensor_id], [site_id])
)

CREATE TABLE [test].[sensors] (
    [sensor_id] int NOT NULL ,
    [measurement_type_id] int NOT NULL,
    [site_id] int NOT NULL ,
    [description] varchar(255) NULL ,
    PRIMARY KEY ([sensor_id], [site_id])
)

我想轻松地从所有这些读数中进行统计。

我想做的一些查询:

Get me all readings for site_id = X between date_hour1 and date_hour2

Get me all readings for site_id = X and sensor_id in <list> between date_hour1 and date_hour2

Get me all readings for site_id = X and sensor measurement type = Z between date_hour1 and date_hour2

Get me all readings for site_id = X, aggregated (average) by DAY between date_hour1 and date_hour2

Get me all readings for site_id = X, aggregated (average) by DAY between date_hour1 and date_hour2 but in UTC+3(这应该给出与之前的查询不同的结果,因为现在日期的开始和结束移动了 3 小时)

Get me min, max, std, mean for all readings for site_id = X between date_hour1 and date_hour2

到目前为止,我一直在使用 Java 来查询数据库并在本地执行所有这些处理。但这最终会有点慢,并且代码编写和维护都很混乱(太多的 cicles、执行重复任务的通用函数、大型/冗长的代码库等)...

更糟糕的是,表readings 很大(因此主键很重要,它也是一个性能指标),也许我应该为此使用 TimeSeries 数据库(有什么好的吗?) .我正在使用 SQL Server。

最好的方法是什么?我觉得我正在重新发明轮子,因为所有这些都是一种分析应用程序......

我知道这些查询听起来很简单,但是当您尝试对所有这些进行参数化时,您最终可能会遇到这样的怪物:

-- Sums all device readings, returns timestamps in localtime according to utcOffset (if utcOffset = 00:00, then timestamps are in UTC)
CREATE PROCEDURE upranking.getSumOfReadingsForDevices
    @facilityId int,
    @deviceIds varchar(MAX),
    @beginTS datetime2,
    @endTS datetime2,
    @utcOffset varchar(6),
    @resolution varchar(6) -- NO, HOURS, DAYS, MONTHS, YEARS
AS BEGIN
    SET NOCOUNT ON -- http://stackoverflow.com/questions/24428928/jdbc-sql-error-statement-did-not-return-a-result-set
    DECLARE @deviceIdsList TABLE (
            id int NOT NULL
    );

    DECLARE @beginBoundary datetime2,
            @endBoundary datetime2;

    SELECT @beginBoundary = DATEADD(day, -1, @beginTS);
    SELECT @endBoundary = DATEADD(day, 1, @endTS);

    -- We shift sign from the offset because we are going to convert the zone for the entire table and not beginTS endTS themselves
    SELECT @utcOffset = CASE WHEN LEFT(@utcOffset, 1) = '+' THEN STUFF(@utcOffset, 1, 1, '-') ELSE STUFF(@utcOffset, 1, 1, '+') END

    INSERT INTO @deviceIdsList
    SELECT convert(int, value) FROM string_split(@deviceIds, ',');

    SELECT SUM(reading) as reading,
           timestamp_local
    FROM (
            SELECT reading,
                   upranking.add_timeoffset_to_datetime2(timestamp_utc, @utcOffset, @resolution) as timestamp_local
            FROM upranking.readings
            WHERE
                device_id IN (SELECT id FROM @deviceIdsList)
                AND facility_id = @facilityId
                AND timestamp_utc BETWEEN @beginBoundary AND @endBoundary
         ) as innertbl
    WHERE timestamp_local BETWEEN @beginTS AND @endTS
    GROUP BY timestamp_local
    ORDER BY timestamp_local
END
GO

这是一个查询,它接收站点 ID(在本例中为 facilityId)、传感器 ID 列表(在本例中为 deviceIds)、开始和结束时间戳,然后是字符串中的 UTC 偏移量,如“+ xx:xx" 或 "-xx:xx",以分辨率结束,该分辨率基本上说明了 SUM 将如何聚合结果(考虑到 UTC 偏移量)。

而且由于我使用的是 Java,乍一看我可以使用 Hibernate 之类的,但我觉得 Hibernate 不是为这些类型的查询而设计的。

【问题讨论】:

  • 你是说“我不会写 SQL 查询”吗?
  • 这与Java无关,请考虑去掉Java标签
  • 就像您的第一个查询字面意思是 SELECT * FROM Sensors s JOIN Readings r on r.sensor_id = s.sensor_id WHERE s.site_id = X AND r.timestamp_utc > early_timestamp AND r.timestamp_utc < late_timestamp - 这是您正在寻找的那种东西吗?
  • 不,这些查询只是基本示例。我在问是否有比这更好的方法:prntscr.com/gh4w44
  • 我不知道,我认为您需要考虑您的实际问题是什么。我会说我认为您最好使用参数化语句编写单个查询而不是数据库过程。这些似乎都不是复杂的东西——这些查询中的每一个都是非常简单的开箱即用 SQL。但就目前而言,看起来您确实是在要求 SO 为您编写查询,这不太可能发生。帮助别人和做免费的咨询工作是有区别的。

标签: java sql database statistics time-series


【解决方案1】:

乍一看,您的结构看起来不错,但看着您的查询,我觉得您可能想尝试一些调整。性能从来都不是一个容易的话题,要找到“一刀切的答案”也不容易。这里有一些注意事项:

  1. 您想要更好的读取写入性能吗?如果你想要更好的 read 性能,你需要重新考虑你的索引。当然你有一个主键,但你的大多数查询都没有使用它(所有三个字段)。尝试为[sensor_id], [site_id] 创建索引。
  2. 可以使用缓存吗?如果某些搜索是经常性的,并且您的应用是数据库的单一入口点,那么请评估您的用例是否会从缓存中受益。
  3. 如果表readings 很大,则考虑使用某种分区策略。查看 MSSQL documentation
  4. 如果您不需要实时数据,请尝试某种搜索引擎,例如Elastic Search

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-19
    • 2021-01-11
    • 1970-01-01
    • 2011-09-02
    • 2014-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多