如何使用窗口函数优化SQL查询

2024-04-25

这个问题与this https://stackoverflow.com/questions/32222889/how-to-calculate-power-consumption-from-power-records/一。我有一个包含设备功率值的表,我需要计算给定时间跨度的功耗并返回 10 个最耗电的设备。我生成了 192 个设备和 7742208 条测量记录(每个设备 40324 条)。这大约是设备一个月内产生的记录量。

对于如此大量的数据,我当前的查询需要 40 多秒才能执行,这太长了,因为时间跨度以及设备和测量的数量可能要高得多。我应该尝试使用与 lag() OVER PARTITION 不同的方法来解决这个问题吗?还可以进行哪些其他优化?我非常感谢带有代码示例的建议。

PostgreSQL 版本 9.4

使用示例值查询:

SELECT
  t.device_id,
  sum(len_y*(extract(epoch from len_x))) AS total_consumption
FROM (
    SELECT
      m.id,
      m.device_id,
      m.power_total,
      m.created_at,
      m.power_total+lag(m.power_total) OVER (
        PARTITION BY device_id
        ORDER BY m.created_at
      ) AS len_y,
      m.created_at-lag(m.created_at) OVER (
        PARTITION BY device_id
        ORDER BY m.created_at
      ) AS len_x
    FROM
      measurements AS m
  WHERE m.created_at BETWEEN '2015-07-30 13:05:24.403552+00'::timestamp
    AND '2015-08-27 12:34:59.826837+00'::timestamp
) AS t
GROUP BY t.device_id
ORDER BY total_consumption
DESC LIMIT 10;

表信息:

    Column    |           Type           |                         Modifiers
--------------+--------------------------+----------------------------------------------------------
 id           | integer                  | not null default nextval('measurements_id_seq'::regclass)
 created_at   | timestamp with time zone | default timezone('utc'::text, now())
 power_total  | real                     |
 device_id    | integer                  | not null
Indexes:
    "measurements_pkey" PRIMARY KEY, btree (id)
    "measurements_device_id_idx" btree (device_id)
    "measurements_created_at_idx" btree (created_at)
Foreign-key constraints:
    "measurements_device_id_fkey" FOREIGN KEY (device_id) REFERENCES devices(id)

查询计划:

Limit  (cost=1317403.25..1317403.27 rows=10 width=24) (actual time=41077.091..41077.094 rows=10 loops=1)
->  Sort  (cost=1317403.25..1317403.73 rows=192 width=24) (actual time=41077.089..41077.092 rows=10 loops=1)
Sort Key: (sum((((m.power_total + lag(m.power_total) OVER (?))) * date_part('epoch'::text, ((m.created_at - lag(m.created_at) OVER (?)))))))
Sort Method: top-N heapsort  Memory: 25kB
->  GroupAggregate  (cost=1041700.67..1317399.10 rows=192 width=24) (actual time=25361.013..41076.562 rows=192 loops=1)
Group Key: m.device_id
->  WindowAgg  (cost=1041700.67..1201314.44 rows=5804137 width=20) (actual time=25291.797..37839.727 rows=7742208 loops=1)
->  Sort  (cost=1041700.67..1056211.02 rows=5804137 width=20) (actual time=25291.746..30699.993 rows=7742208 loops=1)
Sort Key: m.device_id, m.created_at
Sort Method: external merge  Disk: 257344kB
->  Seq Scan on measurements m  (cost=0.00..151582.05 rows=5804137 width=20) (actual time=0.333..5112.851 rows=7742208 loops=1)
Filter: ((created_at >= '2015-07-30 13:05:24.403552'::timestamp without time zone) AND (created_at <= '2015-08-27 12:34:59.826837'::timestamp without time zone))

Planning time: 0.351 ms
Execution time: 41114.883 ms

查询生成测试表和数据:

CREATE TABLE measurements (
    id          serial primary key,
    device_id   integer,
    power_total real,
    created_at  timestamp
);

INSERT INTO measurements(
    device_id,
    created_at,
    power_total
  )
SELECT
  device_id,
  now() + (i * interval '1 minute'),
  random()*(50-1)+1
FROM (
  SELECT
    DISTINCT(device_id),
    generate_series(0,10) AS i
 FROM (
  SELECT
    generate_series(1,5) AS device_id
  ) AS dev_ids
) AS gen_table;

我会尝试将部分计算移至行插入阶段。

添加新列:

alter table measurements add consumption real;

更新专栏:

with m1 as (
    select
        id, power_total, created_at,
        lag(power_total) over (partition by device_id order by created_at) prev_power_total,
        lag(created_at) over (partition by device_id order by created_at) prev_created_at
    from measurements
    )
update measurements m2
set consumption = 
    (m1.power_total+ m1.prev_power_total)*
    extract(epoch from m1.created_at- m1.prev_created_at)
from m1
where m2.id = m1.id;

创建触发器:

create or replace function before_insert_on_measurements()
returns trigger language plpgsql
as $$
declare
    rec record;
begin
    select power_total, created_at into rec
    from measurements
    where device_id = new.device_id
    order by created_at desc
    limit 1;
    new.consumption:= 
        (new.power_total+ rec.power_total)*
        extract(epoch from new.created_at- rec.created_at);
    return new;
end $$;

create trigger before_insert_on_measurements
before insert on measurements
for each row execute procedure before_insert_on_measurements();

查询:

select device_id, sum(consumption) total_consumption
from measurements
-- where conditions
group by 1
order by 1
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用窗口函数优化SQL查询 的相关文章

  • 连接2个表区分大小写

    我有 2 个表 需要获取品牌代码的结果 例如 在数据库中 我有两个不同的品牌 但它们的代码是相同的 只有小写和大写不同 例如 代码名称 关于耐克 和阿迪达斯 如何在代码上内连接 2 个表以分别获取这 2 个表 现在 在内连接之后我得到了这
  • 我写了一个 SQL 查询但没有运行,为什么? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 当前表 EmployeeID CompanyID EmployeeCode EmployeeName 1001 C001 11919 ABC
  • SQL 连接表

    表一包含 ID Name 1 Mary 2 John 表二包含 ID Color 1 Red 2 Blue 2 Green 2 Black 我想结束的是 ID Name Red Blue Green Black 1 Mary Y Y 2 J
  • Postgres 在转换时函数错误/失败时返回空值

    我正在尝试转换text价值观timestamp价值观 对于下表称为a id c1 1 03 03 2000 2 01 01 2000 3 12 4 1990 4 12 Sept 2011 5 12 1 1999 12 33 12 6 24
  • 在 CASE 语句中使用 CAST 时出现数据转换错误

    运行以下命令时出现错误 将数据类型 nvarchar 转换为 float 时出错 declare completeCommand nvarchar max x paramVal nvarchar 100 paramName nvarchar
  • 使用 avg 和 group by 进行 SQL 查询

    我在为 MySQL 编写 SQL 查询时遇到一些问题 我有一个具有以下结构的表 mysql gt select id pass val from data r1 limit 10 id pass val DA02959106 5 00000
  • mysql中相同字符集和排序规则的varchar和nvarchar有什么区别

    谁能告诉我具有相同字符集和整理的 varchar 和 nvarchar 之间有什么区别 例子 varchar CHARACTER SET utf8mb4 COLLATE utf8mb4 unicode ci and nvarchar CHA
  • 从用户定义的函数调用 sql

    SQL Server 2008 是否可以从用户定义函数中的变量执行 sql 或者使用存储过程是唯一的解决方案 我有一条sql语句保存在variabele中 mySqlStatement select from someTable 我想从用户
  • 在 PostgreSQL 中获取 JSONB 的精简版本

    如何获取紧凑型JSONB from PostgreSQL 获取时我得到的只是空格 SELECT data FROM a table WHERE id 1 data is JSONB column unique bla bla foo bar
  • 从两个不同的表中减去值

    考虑表X A 1 2 3 3 6 考虑表 Y A 0 4 2 1 9 如何编写一个查询来获取这两个表之间的差异 以计算下表 例如表 Z A 1 2 1 2 3 目前尚不清楚你想要什么 会是这个吗 SELECT SELECT SUM A FR
  • PostgreSQL 计数查询、物化视图的效率[重复]

    这个问题在这里已经有答案了 可能的重复 PostgreSQL 计数查询优化 https stackoverflow com questions 13075210 optimization of count query for postgre
  • SQL Server 2000 - 将查询分成 15 分钟的块

    我有一个连续时间数据集 我想使用 sql 将其分成 15 分钟的块 如果我能帮忙的话 我不想必须创建一个新表才能做到这一点 i e 时间 计数09 15 109 30 309 45 010 00 210 15 3 有谁知道我该怎么做 我认为
  • 访问:根据记录中的最新日期进行分组(嵌套查询)

    下表中的此查询 SELECT ID Value As of FROM Table a INNER JOIN SELECT ID MAX As of AS As of FROM Table GROUP BY ID b ON a ID b ID
  • 在 Postgresql 中使用标识符重新排序列

    以下代码可以工作并创建一个带有序列号的临时表 该表会为每个新名称重新启动 with results as select row number over partition by name order BY name as mytid nam
  • 如何按月(“年”和“月”)对表进行分区并自动创建每月分区?

    我正在尝试按两者对表进行分区Year and Month 我将通过其进行分区的列是具有 ISO 格式 20150110 20150202 等 的日期时间类型列 例如 我有 2010 年 2011 年 2012 年的销售数据 我希望数据按年份
  • 没有找到适合 jdbc.sqlite 的驱动程序

    所以首先我之前看到过这个问题 我查看了以前的答案并尝试用它来解决我的问题 但是我做不到 我正在创建一个图书馆系统 并为注册类和登录类编写了代码 并为数据库创建了一个类 当我尝试运行该程序时 我收到一条消息 指出没有找到合适的驱动程序 后跟数
  • 如何查询最近7天的总计?

    我正在使用 SQL Server 2008 我想编写一个查询来提供给定天数的总活动量 具体来说 我想统计过去 7 天每天的总票数 我的桌子看起来像这样 VoteID VoteDate Vote BikeID 1 2012 01 01 08
  • 在 Postgres 中以周为单位分割间隔

    这是另一个关于日期的 SQL 问题 我正在使用 PHP 和 Postgres 构建一个日历应用程序 它将显示几天 几周甚至几个月的事件 每个事件都有开始日期和结束日期 按范围选择它们不是问题 然而 如果 Postgres 可以在每周的第一天
  • 快速分类(分箱)

    我有大量条目 每个条目都是浮点数 这些数据x可以通过迭代器访问 我需要使用像这样的选择对所有条目进行分类10
  • 在 Docker Compose 中更改 postgres 容器服务器端口

    我正在尝试使用 Docker compose 在远程服务器上部署第二个数据库容器 该 postgresql 服务器在端口 5433 上运行 而不是第一个 postgresql 容器使用的端口 5432 当我设置应用程序时 我收到以下错误输出

随机推荐

  • 使用 Polyfit 进行垂直线拟合

    这只是一个基本问题 我正在使用拟合线来分散点polyfit 在某些情况下 我的散点具有相同的 X 值并且polyfit无法在其上放置一条线 必须有某种东西可以处理这种情况 毕竟 它只是一个线配合 我可以尝试交换 X 和 Y 然后再画一条线
  • 在 Perl eval 中捕获变量赋值

    我希望能够从 Perl eval 捕获变量赋值 也就是说 确定代码中分配给哪些变量名称并提取它们的值 例如 如果我运行 eval foo 42 bar 3 14 eval 的结果是 3 14 最后评估的值 但我还希望能够确定名称 foo 和
  • 使用 htmlAttributes 正确制作 ActionLink 扩展

    我为我的 ActionLink 使用自定义扩展 我添加了一个属性data url这意味着被翻译成一个属性data url 即用破折号替换下划线 这是使用我的自定义扩展的链接 1 Ajax ActionLink Add MyRoutes Ge
  • 带变量的 ansible regex_search

    如何在ansible playbook中使用正则表达式查找匹配项 其中变量出现在regex search争论 以下剧本在使用以下命令运行时找不到匹配项 ansible playbook playbook yml hosts localhos
  • 程序崩溃后取消警报

    我有一个后台服务 它设置重复警报 执行其任务并自行停止 然后 当闹钟唤醒时 它会再次启动服务 如果程序崩溃 警报仍然存在并唤醒警报广播接收器 有什么方法可以取消崩溃时的警报 我想我也许可以取消任何捕获的异常的警报 但其他原因呢 或者当警报广
  • 新 Maven/Spring MVC 项目的最小 pom.xml 文件

    我对 Maven 和 Spring MVC 完全陌生 我想做的是使用 Maven 设置一个新的 Spring MVC 项目 希望这句话有意义 并使用 Eclipse 在 Tomcat 上运行我的 Web 应用程序 我正在按照此链接上的教程进
  • 为什么 Logstash 需要这么长时间才能启动/加载?

    Edit 我更改了标题 因为问题不是我最初想象的那样 事实是 logstash 需要超过一分钟开始 这可能会被误解为 沉默 我正在尝试让logstash运行 所以我按照官方网站上的说明进行独立安装 http logstash net doc
  • 为什么 NSURLSession uploadTaskWithRequest:fromData: 无法上传到 php 服务器?

    php 代码工作正常 我已经从同一服务器上的 html 表单上传了文件 上传的文件大小从 40K 到 2 0M 不等 因此其大小不高 在运行 PHP 5 3 的服务器上激活文件上传 我发现了很多这样的帖子 还没有答案 https stack
  • 绑定到 ViewModel 和 CodeBehind 中的属性

    我确信这是一个可笑的无知问题 但无论如何我还是要问这个问题 因为我搜索了又搜索 要么不理解我所看到的解决方案 要么没有找到我所寻求的答案 我有一个 MVVM 应用程序 我的 XAML 设置为 VM 的 DataContext 其中屏幕上的数
  • 将表部署到表存储中的最佳方法

    你能让我知道吗 进行表存储部署的最佳方法是什么 因为我的开发团队询问他们有很多表 每个表都有数千个条目 因此 他们要求我咨询任何微软团队或博客人们检查进行表存储部署的最佳方法 您知道我们该怎么做吗 因为脚本每次都会耗尽和插入数千个条目 我们
  • Windows 7 上的 VirtualBox 端口转发不起作用

    Windows 7 上的 VirtualBox 端口转发不起作用 我尝试通过端口转发从我的 Windows 7 主机 ssh 到我的 VirtualBox 但 VirtualBox 不会打开端口进行侦听 我可以通过打开 VirtualBox
  • 如何在 Cocoa 中检查文件是否被锁定?

    有没有API可以检查文件是否被锁定 我在中找不到任何 APINSFileManagerclass 让我知道是否有任何API可以检查文件的锁定 我发现以下与文件锁定相关的链接 http lists apple com archives coc
  • 使用 MVC 和 DAO 模式在 JSP 页面中的 HTML 中显示 JDBC 结果集

    我正在使用 JSP 和 JDBC 实现 MVC 我已将数据库类文件导入到 JSP 文件中 并且想显示数据库表的数据 我不知道该如何归还ResultSet从 Java 类到 JSP 页面并将其嵌入到 HTML 中 我怎样才能实现这个目标 在设
  • 从命令行安装 Oracle 客户端,无需用户交互

    我正在寻找一种在 Windows 上安装 Oracle 客户端但从命令行运行的方法 为了自动运行它应有没有用户交互 对于 Oracle Universal Installer 的命令行选项 Oracle 文档非常稀疏 即使运行设置为setu
  • Golang 结构继承没有按预期工作?

    查看这个沙箱 https play golang org p elIHgHAZjT 声明从不同结构继承的结构时 type Base struct a string b string type Something struct Base c
  • 可以在没有 dynamoDB 的情况下使用 AWS App-Sync

    我对 Amazon app sync 的离线和同步功能感兴趣 但我想知道它是否可以在没有 dynamoDB 作为后端的情况下使用 用 VTL 为 dynamoDB 编写的 graphQL 解析器看起来很糟糕 看来使用 mongo 后端会好得
  • 是否可以在越狱的ios上使用外部键盘模拟触摸事件?

    是否可以在 iOS 越狱以及越狱涉及的所有元素上模拟特定屏幕坐标中的触摸事件 按下物理外部键盘 通过相机连接套件或蓝牙的 USB 上的特定按键 我会用它来用脚按下应用程序 振幅 中的按钮 我想使用键盘作为脚踏开关 仅供私人使用 没有应用商店
  • 如何使用 OData 在单个 POST 请求中正确创建和链接一对一关系

    在 OData Operations 文档的第 2 4 节第四段中 它写道 在使用 POST 创建实体时 也可以在同一请求中创建链接 但是 我在尝试完成这项工作时遇到了麻烦 在创建时就多对多链接提出了类似的问题 看起来如果没有批量请求 就不
  • 将 CVC 传递给 stripe.createPaymentMethod JS?

    我需要 CVC 和 Expiry 的单独输入 因此我创建了 3 个 Stripe 元素 let elements stripe elements let cardNumber elements create cardNumber cardN
  • 如何使用窗口函数优化SQL查询

    这个问题与this https stackoverflow com questions 32222889 how to calculate power consumption from power records 一 我有一个包含设备功率值