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查询数据库,并在本地执行所有这些处理。但是这样做的速度有点慢,代码编写和维护起来也很混乱(太多的循环、执行重复任务的通用函数、庞大/冗长的代码库等等)
更糟糕的是,tablereads
非常庞大(因此主键非常重要,它也是一个性能索引),也许我应该为此使用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。但从目前的情况来看,您确实要求这样做是为了为自己编写查询,这是不太可能发生的。帮助别人和做免费咨询工作是有区别的。