【发布时间】:2020-03-24 08:55:46
【问题描述】:
我管理一个数据库,其中包含从各个站点收集的大量气候数据。这是一个 Oracle 12.2 DB,下面是相关表的概要:
FACT = 在特定时间的单独测量
- UTC_START = 开始测量的 UTC 时间
- LST_START = 开始测量的本地标准时间(到特定站点)的时间
- SERIES_ID = 测量所属系列的 ID(FK 到 SERIES)
- STATION_ID = 发生测量的台站 ID(FK 到 STATION)
- VALUE = 测量值
请注意,每个站的 UTC_START 和 LST_START 始终具有恒定的差异(LST 与 UTC 的偏移)。我已经确认没有任何情况下 UTC_START 和 LST_START 之间的差异超出预期。
SERIES = 数据系列的描述性数据
- SERIES_ID = 系列 ID (PK)
- NAME = 系列的文本名称(例如温度)
STATION = 台站的描述性数据
- STATION_ID = 电台 ID (PK)
- SITE_ID = 站点所在站点的 ID(大多数站点有一个站点,但少数站点有 2 个)
- SITE_RANK = 站点内站点的排名(如果站点超过 1 个)。
- EXT_ID = 网站的外部 ID(提供给我们)
站点的 EXT_ID 适用于该站点的所有站点(但可能不会填充,除非 SITE_RANK == 1,不理想,我知道,但不是这里的问题),并且首选来自排名较低的站点的数据。为了将这些数据组织成可使用的格式,我们使用 PIVOT 将在同一地点/时间发生的测量数据收集到行中。
这是查询:
WITH
primaries AS (
SELECT site_id, ext_id
FROM station
WHERE site_rank = 1
),
data as (
SELECT d.site_id, d.utc_start, d.lst_start, s.name, d.value FROM (
SELECT s.site_id, f.utc_start, f.lst_start, f.series_id, f.value,
ROW_NUMBER() over (PARTITION BY s.site_id, f.utc_start, f.series_id ORDER BY s.site_rank) as ORDINAL
FROM fact f
JOIN station s on f.station_id = s.station_id
) d
JOIN series s ON d.series_id = s.series_id
WHERE d.ordinal = 1
AND d.site_id = ?
AND d.utc_start >= ?
AND d.utc_start < ?
)
records as (
SELECT * FROM data
PIVOT (
MAX(VALUE) AS VALUE
FOR NAME IN (
-- these are a few series that we would want to collect by UTC_START
't5' as t5,
'p5' as p5,
'solrad' as solrad,
'str' as str,
'stc_05' as stc_05,
'rh' as rh,
'smv005_05' as smv005_05,
'st005_05' as st005_05,
'wind' as wind,
'wet1' as wet1
)
)
)
SELECT r.*, p.ext_id
FROM records r JOIN primaries p on r.site_id = p.site_id
这就是事情变得奇怪的地方。此查询在 SQLAlchemy、IntelliJ(使用 OJDBC Thin)和 Orcale SQL Developer 中完美运行。但是,当它在我们的 Java 程序中运行时(相同的 JDBC url 和凭据,使用普通的旧 JDBC 语句和结果集),它会给出没有意义的结果。特别是对于同一个站,它将返回 2 行具有相同的 UTC_START,但不同的 LST_START(回想一下,我已经验证了这个 100% 不会出现在 FACT 表的任何地方)。为了确保不会发生奇怪的参数处理,我们测试了占位符的硬编码值,并在各个客户端之间复制并粘贴了完全相同的查询,唯一返回这些奇怪结果的是 Java 程序(它使用与 IntelliJ 完全相同的 OJDBC jar)。
如果有人有任何见解或可能的原因,将不胜感激。我们现在有点不知所措。
【问题讨论】:
-
UTC_START和LST_START的数据类型是什么?由于时区不同,这听起来像是一些转换.. -
它们都是 DATE,但 LST_START 只是 UTC_START 加上 UTC 偏移量(即它是从 UTC_START 计算的,而不是直接观察到的)。而且我已经验证了 UTC_START 和 LST_START 对于 FACT 中的每一行都有适当的差异。实际上没有明确的时区转换本身,它只是一个简单的加法操作
-
尝试在 CTE 查询中使用 /*+ MATERIALIZE */ 或 /*+ INLINE */ 提示。如果相同的 SQL 返回不同的结果,则取决于 Exec。计划的话,肯定是Oracle BUG。在引入 12c 版本时,以一种新的方式对 GROUP BY 评估存在一些令人讨厌的错误。
-
@ibre5041 任何一个提示都会发生同样的事情。在执行计划的注释中,通过 IntelliJ 或 Java 运行时的步骤是相同的,但由于某种原因,Java 版本的估计成本要小得多
-
您确定这不是 Java 程序显示或输出结果数据的方式问题,而不是 Oracle 返回的数据不正确吗?
标签: java sql oracle jdbc oracle12c