联合选择的条件偏移
Posted
技术标签:
【中文标题】联合选择的条件偏移【英文标题】:Conditional offset on union select 【发布时间】: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_date
WHERE field2 = last_field_id
我希望高水位线至少是排序/索引的主要部分。而且,由于您的数据模型已经瘫痪,您可以考虑使用临时表或 marerialized 视图。
@joop 我在只读副本中工作时无法使用临时表。对不起,我没有在我的问题中提到这个,所以我会更新它
如果你无论如何都必须使用所有UNION ALL
,我相信row_number over()
对于分页来说并没有那么难看
@VaoTsun 我不太明白你的说法,抱歉。你能澄清一下吗?
我的意思是当你union all
所有桌子时,大部分成本都来了。可能下一个最昂贵的是子选择?..所以我说在这里使用row_number
并不难看。 - 也许我误解了你?
【参考方案1】:
你已经成功地把自己逼到了一个狭窄的地方。该查询及其ORDER BY
表达式与您的分页要求相矛盾。
ORDER BY order_date
不是 确定性 排序顺序(可能有多行具有相同的 order_date
) - 您需要在你在这里做任何其他事情之前。 field2
似乎也不是独一无二的。您需要两者:定义确定性排序顺序和页面结束/开始的唯一指示符。理想情况下,指示器匹配排序顺序。可能是(order_date, field2)
,这两个列都定义了NOT NULL
,以及UNIQUE
的组合。您的限制 "only field2 value is acceptable"
与您的查询相矛盾。
这就是所有之前考虑如何获得最佳性能...
有行值和多列索引用于分页的经过验证的解决方案:
Optimize query with OFFSET on large table但是从多个源表的组合中提取数据会使事情变得复杂。优化取决于您的设置细节。
如果您无法获得所需的性能,您唯一剩下的选择就是以某种方式具体化查询结果。临时表、光标、物化视图 - 最好的工具取决于您的设置细节。
Of course, general performance tuning might help, too.
【讨论】:
以上是关于联合选择的条件偏移的主要内容,如果未能解决你的问题,请参考以下文章