1

我有一个巨大的表格,其中包含来自工业机器的监控数据。该表有 30 个所谓的参数列,典型的查询每次选择 2 - 7 个。诸如图表和状态表之类的东西是从结果中计算出来的。大多数计算要求除了给定时间范围内的值(主数据)之外,还需要知道给定时间范围(前数据)之前参数的最新非空值。

我目前使用查询每个参数执行的预数据。这不像我想要的那样有效,因为它向数据库引入了n 个查询,其中n是计算所需的参数数量。是否有可能通过单个查询获取预数据(有关当前查询的示例,请参见下文)?

数据前查询示例(也为fuel_cons、pwr_on 和idle_counter 执行):

SELECT
    alert_f335
FROM
    signal_value SIGV
    ,machine M /*Using old join since this is actually a Hibernate query*/
WHERE
    M.serialNumber = 'R451902'
    AND SIGV.machineId = M.id
    AND SIGV.time = (
        SELECT
            MAX(TMP.time)
        FROM
            signal_value TMP
        WHERE
            TMP.machineId = M.id
            AND TMP.time < 1370044800000 /*2013-06-01 00:00:00*/
            AND TMP.alert_f335 IS NOT NULL
    )
ORDER BY
    SIGV.time ASC

主数据查询示例(可以):

SELECT
    alert_f335
    ,fuel_cons
    ,pwr_on
    ,idle_counter
FROM
    machine M
INNER JOIN
    signal_value SIGV
    ON M.id = SIGV.machineId
WHERE
    M.serialNumber = 'R451902'
    AND SIGV.time >= 1370044800000 /*2013-06-01 00:00:00*/
    AND SIGV.time <= 1371340799000 /*2013-06-15 23:59:59*/
    AND (alert_f335 IS NOT NULL OR fuel_cons IS NOT NULL OR pwr_on IS NOT NULL OR idle_counter IS NOT NULL)
ORDER BY
    SIGV.time ASC

机器表有 2 个有趣的列:id 和序列号。signal_value 除了参数列之外还有 2 个有趣的列:machineId、time (millis)。

4

1 回答 1

0

这取决于结果的来源。让我们看看你在数据前查询中做了什么。您基本上是在寻找 alert_f335 不为空的那一行(加上其他一些过滤器)。让我们将该行称为 A。现在让我们考虑下一列,fuel_cons。如果该行的正确行始终是 A 行,那么这很简单,只需将它们全部粘贴到查询的选择部分即可。但是你已经经历了所有这些麻烦来发布这个问题,所以我假设它们不是同一行。

所以在某种程度上,有人需要执行多个查询。您可以像现在一样通过发送不同的查询从应用程序代码中执行此操作,或者您要求 SQL Server 运行多个查询。您可以将这些查询隐藏为子查询,但最终结果是 SQL Server 几乎需要运行 4 次。当您设法将这些组合起来时,您会看到执行计划有循环或只是平展了多个分支,可能是多个分支。因此,您不会从合并它们中获得太多收益。

话虽如此,您可以获得一点点。这 4 个查询将在大部分情况下共享相同的过滤器,因此您可以告诉 SQL Server 它们是相同的查询,因此它至少会重用其在表假脱机或索引中的位置或它决定执行的任何操作。现在,如果您有良好的索引,那么它的重要性就很小了。我会坚持写更容易写的东西。

至于实际合并它们,我会使用 CTE 创建这个临时子表,然后使用 4 个子查询将它们全部放在同一行中:

with M as (
    select * from machine where id = 'R451902'
), TMP as (
    select * from signal_value 
    join M on M.id = signal_value.machineID
    where signal_value.time < 1370044800000
)
select 
    (select top 1 alert_f335 from TMP where alert_f335 is not null order by TMP.time DESC)
    ,(select top 1 fuel_cons from TMP where fuel_cons is not null order by TMP.time DESC)
    ,(select top 1 pwr_on  from TMP where pwr_on  is not null order by TMP.time DESC)
    ,(select top 1 idle_counter from TMP where idle_counter is not null order by TMP.time DESC)
于 2013-06-27T18:46:57.973 回答