我在PostgreSQL 8.2的分叉版本上已经适应了MPP。我试图从两个较大的表格中计算出一系列最佳下界的最大下界。这里是前述方式表的例子:优化涉及一组时间最大下界的查询PostgreSQL
Table A
|source_ip (inet type) |s_time (date type) |
------------------------------------------------
|10.50.43.200 | 2013-02-21 01:47:08 |
|10.50.43.200 | 2013-02-21 01:47:38 |
|10.50.43.200 | 2013-02-21 01:47:41 |
|10.50.43.200 | 2013-02-25 17:05:00 |
|10.50.43.200 | 2013-02-25 17:05:03 |
|10.50.43.200 | 2013-02-25 17:05:04 |
|10.50.43.200 | 2013-02-25 17:05:34 |
|10.50.43.200 | 2013-02-25 17:10:01 |
|10.50.43.200 | 2013-02-25 17:12:52 |
Table B
|source_ip (inet type) |mac (macaddr type) |l_time (date type) |
----------------------------------------------------------------------
|10.50.43.200 | 00:24:d7:99:e9:0c | 2013-02-20 22:33:47 |
|10.50.43.200 | 00:24:d7:99:e9:0c | 2013-02-20 23:07:32 |
|10.50.43.200 | 00:24:d7:99:e9:0c | 2013-02-20 23:13:04 |
|10.50.43.200 | 00:24:d7:99:e9:0c | 2013-02-21 00:02:56 |
|10.50.43.200 | 00:24:d7:99:68:14 | 2013-02-25 17:04:56 |
|10.50.43.200 | 00:24:d7:99:68:14 | 2013-02-25 17:04:59 |
|10.50.43.200 | 00:24:d7:99:68:14 | 2013-02-25 17:26:15 |
对于表A
我想加入一个附加列,那就是“最大下界”为表B
每个时间戳的每一行。也就是说,我想要一个包含表B中所有值中的最大时间的列,并且也小于或等于表A
中的相应时间。我期待的输出将类似于以下内容:
OUTPUT
------------------------------------------------------------
|10.50.43.200 |2013-02-21 01:47:38 |2013-02-21 00:02:56 |
|10.50.43.200 |2013-02-21 01:47:41 |2013-02-21 00:02:56 |
|10.50.43.200 |2013-02-25 17:05:00 |2013-02-25 17:04:59 |
|10.50.43.200 |2013-02-25 17:05:03 |2013-02-25 17:04:59 |
|10.50.43.200 |2013-02-25 17:05:04 |2013-02-25 17:04:59 |
|10.50.43.200 |2013-02-25 17:05:34 |2013-02-25 17:04:59 |
下面的查询是什么,我想出了,但我不知道,如果使用max()
聚合函数是实现这一目标的最佳方式。
所以,我的问题是 - 我们可以在不使用max()
的情况下重写下面的查询,以便在大型数据集(在100多万个范围内)更快?
SELECT a.source_ip,
a.s_Time, max(b.l_Time) AS max_time
FROM table_a AS a
INNER JOIN
table_b AS b
ON (a.source_ip = b.source_ip AND a.s_time > b.l_time)
GROUP BY a.source_ip, b.sourcemac, a.s_time
ORDER BY a.s_time asc;
这里是解释计划:
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------
Gather Motion 72:1 (slice1; segments: 72) (cost=1519175930.51..1519305453.91 rows=143915 width=48)
-> HashAggregate (cost=1519175930.51..1519305453.91 rows=143915 width=48)
Group By: a.source_ip, a.s_time
-> Hash Join (cost=991681.79..1169135585.55 rows=648222862 width=23)
Hash Cond: a.source_ip = b.source_ip
Join Filter: a.s_time > b.l_time
-> Append-only Columnar Scan on a (cost=0.00..1083707.12 rows=1439149 width=15)
-> Hash (cost=487360.24..487360.24 rows=560358 width=15)
-> Seq Scan on b (cost=0.00..487360.24 rows=560358 width=15)
(9 rows)
我知道我可以哈希source_ip
-s来bigints更快的连接。我也认为可能值得尝试索引连接中使用的列,但我不确定最佳优化策略是什么,并且会喜欢来自StackOverflow社区优秀专家组的任何输入。我们也尝试了rank()
窗口函数,但是它在我们正在使用的实现上存在问题,并且是我们测试过的这种类型的查询性能最差的函数,所以理想的策略将有望避免任何窗口函数。
编辑:添加一个索引上source_ip
,start_yime
为表A
和重写使用LIMIT 1
建议在后查询:
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------
Gather Motion 72:1 (slice2; segments: 72) (cost=1624120.24..7442384075819.75 rows=145921 width=48)
-> HashAggregate (cost=1624120.24..7442384075819.75 rows=145921 width=48)
Group By: a.src, a.start_time
-> Append-only Columnar Scan on a (cost=0.00..1098806.16 rows=1459206 width=15)
SubPlan 1
-> Limit (cost=708374.49..708374.51 rows=1 width=15)
-> Limit (cost=708374.49..708374.49 rows=1 width=15)
-> Sort (cost=708374.49..708376.35 rows=11 width=15)
Sort Key (Limit): b.source_ip, b.start_time
-> Result (cost=708339.65..708347.10 rows=11 width=15)
Filter: $0 = b.source_ip AND $1 > b.start_time
-> Materialize for deadlock safety (cost=708339.65..708347.10 rows=11 width=15)
-> Broadcast Motion 72:72 (slice1; segments: 72) (cost=0.00..708338.90 rows=11 width=15)
-> Seq Scan on b (cost=0.00..708338.90 rows=11 width=15)
什么指数的定义? –
请将包含索引和相关部分配置参数的表结构添加到问题中。 (看起来你已经将work_mem设置为一个非常大的值)BTW:pg-8.2是非常古老的。 – wildplasser