【发布时间】:2016-10-27 09:57:55
【问题描述】:
考虑我们从几十个结构不同但字段含义相似的表中进行复杂的联合选择:
SELECT a1.abc as field1,
a1.bcd as field2,
a1.date as order_date,
FROM a1_table a1
UNION ALL
SELECT a2.def as field1,
a2.fff as field2,
a2.ts as order_date,
FROM a2_table a2
UNION ALL ...
ORDER BY order_date
另请注意,结果通常按“合成”字段order_date 排序。
这个查询提供了大量的行,我们想要处理这组行中的页面。每个页面由两个参数定义:
- 页面大小
-
field2上一页最后一项的值
我们无法改变最重要的事情可以定义页面的方式。 IE。不能使用上一页最后一项日期的行号:只能接受 field2 值。
当前的分页算法以非常丑陋的方式实现:
1) 上面的查询被包装在带有row_number() 附加列的附加选择中,然后被包装在存储过程union_wrapper 中,它返回适当的
table ( field1 ..., field2 character varying),
2) 然后执行复杂选择:
RETURN QUERY
with tmp as (
select
rownum, field1, field2 from union_wrapper()
)
SELECT field1, field2
FROM tmp
WHERE rownum > (SELECT rownum
FROM tmp
WHERE field2 = last_field_id
LIMIT 1)
LIMIT page_size
问题是我们必须在内存中构建完整的联合选择结果,以便稍后检测我们要从中剪切新页面的行号。这是相当缓慢的,并且需要很多时间来执行。
是否有任何方法可以重新配置此操作以显着降低查询复杂性并提高其速度?
再说一遍:我们不能改变分页条件,我们不能改变表的结构。行检索的唯一方式。
UPD:我也不能使用临时表,因为我在数据库的只读副本中工作。
【问题讨论】:
-
ORDER BY order_dateWHERE field2 = last_field_id我希望高水位线至少是排序/索引的主要部分。而且,由于您的数据模型已经瘫痪,您可以考虑使用临时表或 marerialized 视图。 -
@joop 我在只读副本中工作时无法使用临时表。对不起,我没有在我的问题中提到这个,所以我会更新它
-
如果你无论如何都必须使用所有
UNION ALL,我相信row_number over()对于分页来说并没有那么难看 -
@VaoTsun 我不太明白你的说法,抱歉。你能澄清一下吗?
-
我的意思是当你
union all所有桌子时,大部分成本都来了。可能下一个最昂贵的是子选择?..所以我说在这里使用row_number并不难看。 - 也许我误解了你?
标签: sql postgresql pagination plpgsql query-performance