Java 对SQL表进行统计

Java 对SQL表进行统计,java,sql,database,statistics,time-series,Java,Sql,Database,Statistics,Time Series,我的数据库中有一个表,我用这种方式记录了几个传感器的读数: 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 KE

我的数据库中有一个表,我用这种方式记录了几个传感器的读数:

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])
)
我想很容易地从这些读数中得出统计数据

我想提出一些问题:

获取date\u hour1和date\u hour2之间站点id=X的所有读数

获取日期1和日期2之间站点id=X和传感器id的所有读数

获取date_hour1和date_hour2之间站点id=X和传感器测量类型=Z的所有读数

获取站点id=X的所有读数,在日期1和日期2之间按天汇总(平均值)

获取站点_id=X的所有读数,在日期_hour1和日期_hour2之间按天聚合(平均),但以UTC+3为单位
(这将给出与之前查询不同的结果,因为现在天的开始和结束被移动了3h)

Get me min,max,std,date\u hour1和date\u hour2之间站点id=X的所有读数的平均值

到目前为止,我一直在使用Java查询数据库,并在本地执行所有这些处理。但是这样做的速度有点慢,代码编写和维护起来也很混乱(太多的循环、执行重复任务的通用函数、庞大/冗长的代码库等等)

更糟糕的是,table
reads
非常庞大(因此主键非常重要,它也是一个性能索引),也许我应该为此使用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列表(在本例中为DeviceID)、开始和结束时间戳的查询,后跟UTC偏移量(如“+xx:xx”或“-xx:xx”)字符串,以解析结束,解析基本上表示如何通过求和聚合结果(考虑UTC偏移)


由于我使用的是Java,乍一看,我可以使用Hibernate或其他什么,但我觉得Hibernate并不是为这些类型的查询而设计的。

您的结构乍一看很好,但看看您的查询,我觉得您可能想尝试一些调整。性能从来都不是一个容易的主题,也不是一个简单的问题sy希望找到“一刀切”的答案。以下是一些注意事项:

  • 您想要更好的读写性能吗?如果您想要更好的读性能,您需要重新考虑索引。确保您有主键,但大多数查询都没有使用它(所有三个字段)。请尝试为
    [sensor\u id]、[site\u id]
    创建索引
  • 你能使用缓存吗?如果一些搜索是重复的,并且你的应用程序是数据库的单一入口点,那么请评估你的用例是否会从缓存中受益
  • 如果表<代码>读数是巨大的,那么考虑使用某种分区策略。
  • 如果你不需要实时数据,那么试试搜索引擎,比如

  • 你是说“我不知道如何编写SQL查询”这与java无关,请考虑删除java的标签,你的第一个查询是非常正确的,从传感器S的Read Re读物R上的R.SyrWorxID=S.SysRoSoRID中选择。UESRIE只是一些基本的例子。我想问的是,是否还有比这更好的方法:我不知道,我认为你需要思考你的实际问题是什么。我会说,我认为你最好用参数化语句编写个人查询,而不是数据库过程。所有这些看起来都不是复杂的东西——每一个查询s是一个非常简单的开箱即用的SQL。但从目前的情况来看,您确实要求这样做是为了为自己编写查询,这是不太可能发生的。帮助别人和做免费咨询工作是有区别的。