【发布时间】:2014-06-13 21:24:40
【问题描述】:
我有以下查询,运行大约需要 15-20 秒。
cte0 为 ( 选择 标签, 日期, 案子 什么时候 Lead(label || date || "number") OVER (PARTITION BY label || date || "number" ORDER BY "label", "date", "number", "time") IS NULL 然后 '1':: 数字 别的 '0':: 数字 END 作为“唯一” FROM 表数据 LEFT JOIN table_mapper ON table_mapper."type" = table_data."type" 日期在 date_trunc('month', current_date - 1) 和 current_date - 1 之间的日期 ) 选择“MTD”作为“标签”,round(sum(“unique”) / count(“unique”) *100,1) 作为“value” FROM cte0 WHERE “date” BETWEEN date_trunc('month', current_date - 1)和 current_date -1 联合所有 SELECT 'Week' 作为“标签”,round(sum(“unique”) / count(“unique”) *100,1) 作为“value” FROM cte0 WHERE “date” BETWEEN date_trunc('week', current_date - 1)和 current_date -1 联合所有 选择“FTD”作为“标签”,round(sum(“unique”) / count(“unique”) *100,1) 作为“值” FROM cte0 WHERE “date” = current_date -1在table_data 表中,我在date 列上有一个索引。
表定义(\d table_data)
表“public.table_data”
专栏 |类型 |修饰符
------------------+------------------------+------ -----
日期 |日期 |不为空
号码 |大整数 |不为空
时间 |没有时区的时间|不为空
结束时间 |没有时区的时间|不为空
持续时间 |整数 |不为空
时间1 |整数 |不为空
时间2 |整数 |不为空
时间3 |整数 |不为空
时间4 |整数 |不为空
时间5 |整数 |不为空
时间6 |整数 |不为空
时间7 |整数 |不为空
类型 |正文 |不为空
姓名 |正文 |不为空
id1 |整数 |不为空
id2 |整数 |不为空
关键 |整数 |不为空
状态 |正文 |不为空
索引:
“ix_cli_date” btree(日期)
表定义 (\d table_mapper)
解释查询的分析
结果(成本=184342.66..230332.86 行=3 宽度=64)(实际时间=23377.923..25695.478 行=3 循环=1)" 热膨胀系数 cte0" -> WindowAgg(成本=121516.06..156751.65 行=612793 宽度=23)(实际时间=14578.000..18985.958 行=696157 循环=1)” -> 排序(成本=121516.06..123048.04 行=612793 宽度=23)(实际时间=14577.975..17084.405 行=696157 循环=1)” 排序键:(((table_mapper.label || (table_data.date)::text) || (table_data."number")::text)), table_mapper.label, table_data.date, table_data."number", table_data 。“时间”” 排序方法:外部合并磁盘:39480kB" -> Hash Left Join (cost=11.96..37474.21 rows=612793 width=23) (实际时间=1.449..3308.718 rows=696157 loops=1)" 哈希条件:(table_data."type" = table_mapper."type")" -> 在 table_data 上使用 ix_cli_date 进行索引扫描(成本=0.02..29036.36 行=612793 宽度=38)(实际时间=0.141..946.648 行=696157 循环=1)" 索引条件:((date >= date_trunc('month'::text, ((('now'::text)::date - 1))::timestamp with time zone)) AND (date Hash (cost=7.53 ..7.53 行=353 宽度=25) (实际时间=1.275..1.275 行=336 循环=1)" 存储桶:1024 批次:1 内存使用量:15kB" -> table_mapper 上的 Seq Scan (cost=0.00..7.53 rows=353 width=25) (实际时间=0.020..0.589 rows=336 loops=1)" -> 追加(成本=27591.00..73581.21 行=3 宽度=64)(实际时间=23377.920..25695.467 行=3 循环=1)” -> 聚合(成本=27591.00..27591.02 行=1 宽度=32)(实际时间=23377.917..23377.918 行=1 循环=1)” -> cte0上的CTE扫描(成本=0.00..27575.68行=3064宽度=32)(实际时间=14578.052..22335.236行=696157循环=1)” 过滤器:((date = date_trunc('month'::text, ((('now'::text)::date - 1))::timestamp with time zone)))" -> 聚合(成本=27591.00..27591.02 行=1 宽度=32)(实际时间=1741.509..1741.510 行=1 循环=1)” -> cte0上的CTE扫描(成本=0.00..27575.68行=3064宽度=32)(实际时间=20.009..1522.352行=168261循环=1)” 过滤器:((date = date_trunc('week'::text, ((('now'::text)::date - 1))::timestamp with time zone)))" -> 聚合(成本=18399.11..18399.13 行=1 宽度=32)(实际时间=576.029..576.030 行=1 循环=1)” -> cte0上的CTE扫描(成本=0.00..18383.79行=3064宽度=32)(实际时间=9.308..546.735行=23486循环=1)” 过滤器:(date = (('now'::text)::date - 1))" 总运行时间:25710.506 ms"说明:
我从 table_data 获取唯一计数和重复计数,而 LEAD 帮助我解决了我为列的最后一个重复值赋予值 0 的位置。
假设我在一列中有 3 个x。我将1 的值赋予前2 个x,第三个x 赋予0。
实际上,通过cte,我从表table_data 中取出整行,并使用前导进行一些计算,并在定义的日期范围内连接字符串,其中每行1 和0 的值为根据标准定义。
如果前导为空,则计为 1,如果不为空,则计为 0。
我分别返回 3 行 MTD、Current Week 和 FTD,并计算我从领先者那里得到的 sum() 和 count(*) 整行。
对于 MTD,我有当月的总和和计数。
一周 - 这是本周,FTD 是昨天。
【问题讨论】:
-
您执行此字符串连接:
Lead(label || date || "number") OVER (PARTITION BY label || date || "number" ORDER BY "label", ...仅检测组的开头?为什么不使用 raw 字段呢? -
我在您的表定义中没有看到主键。是否缺少任何其他约束或索引?最好在
psql中展示您使用\d table_data得到的结果,而不是一些手工制作的代理。 -
其实我是个新手。我需要在 SQL 编辑器中运行
\d table_data吗?顺便说一句,我没有为主列创建任何列。 -
psql 是 PostgreSQL 的默认命令行界面。每个表都应该有一个primary key。另外,最好不要使用reserved words作为标识符。
-
好。缺少的是描述。请添加一些解释查询应该实现的目标。
标签: sql database performance postgresql query-optimization