Paginated UNION ALL结果 - 最佳表现

时间:2017-08-16 16:23:13

标签: sql sql-server tsql

我们需要将4个不同表的结果合并为一个列表并通过OFFSET / FETCH对其进行分页。

想要从表a,b,c和amp;中选择记录的内容d,按CreatedDatetime和OFFSET X,FETCH Y排序它们。表格相当大(就行数而言)而且只做UNION ALL然后分页这听起来很可怕因为它可能意味着可能编译整个记录列表然后采取分页部分。

问题是没有一个表可以作为提取开始/结束日期时间窗口的参考,因为每个集合可能但也可能不包含来自任何表的记录。例如,结束结果可能包含来自表a; a/b; a/b/c; a/b/c/d; b; b/c;....的任意组合的记录,我们需要返回固定大小的数字(分页大小,例如,为20)。

关于如何最有效地解决这个问题的任何想法?

更新

基于来自@HABO的问题 遗憾的是,没有关于查询的特殊线索。我们正在系统中显示用户活动。它有不同的种类(我们选择的表格)。现在,查询会弹出查看活动的管理员的数据。管理员如何查看数据可能会有很大差异:一些用户在过去几个小时内将有数千个活动,管理员希望全部查看。在其他情况下,用户每天将有3个操作,管理员只会看到第一页数据。

PS。它不是纯日志表,因为随着时间的推移,活动充当状态机,每个状态都有自己的状态,我们也会在这些查询中查找。

3 个答案:

答案 0 :(得分:1)

如果您知道页面大小(例如100),那么您可以简单地编写4个前100个查询(按创建日期排序) - 然后对结果执行Union ALL。 这样,即使所有前100条记录都来自1张表格,您也可以参与其中。

对于后续分页查询 - 您需要记录每个表中最后显示的行,并将其用作下一次获取的高水位标记 - (选择前100个FROM TableA其中RowID> @HighWater)

应该相当有效......

答案 1 :(得分:0)

这是缓存有用的地方。您可以在应用程序层中缓存查询结果,如果它不是太大则在那里进行分页,或者如果查询结果很大,则将查询结果缓存在表(或临时表)中。

答案 2 :(得分:0)

我想会有过滤器。根据你的说法,这些可能会有很大不同。因此,在最糟糕的情况下,所有列都可以是过滤器。 我的建议是使用5个视图,每个表一个,最后一个联合它们。只需确保所有过滤器列尽可能直接在物理表上运行。 最后,选择主视图和获取,但要注意order by子句。确保order by具有唯一的数据组合,否则您可能会遇到行在简单的普通刷新上更改页面的情况。如果按定义的用户顺序,强制在末尾添加一些键列。

如何通过为100%安全获取/偏移提供不同的值来安全地确保订单:

在4个视图中创建一个新的列,其中包含一个简单的常数作为值,例如1,2,3,4 AS [TableSource] 确保选择每个表的PK。如果没有,则必须在视图中创建一个,可能使用ROW_NUMBER或NEWID,例如[Pk]。 最后,从主视图中进行选择时,您可以按顺序创建CreateDate,Pk,TableSource。这样你100%安全,在同一组数据中,任何行都将完全放在同一位置,从而产生正确的分页。

通过CreateDate安全隔离30行页面的示例:

SELECT * FROM (
SELECT src, id, ROW_NUMBER() OVER(ORDER BY dt DESC,src,id)rn FROM (
SELECT 1 src, id, dt FROM table1 /*WHERE x=y*/ UNION ALL 
SELECT 2 src, id, dt FROM table2 /*WHERE x=y*/ UNION ALL 
SELECT 3 src, id, dt FROM table3 /*WHERE x=y*/ UNION ALL 
SELECT 4 src, id, dt FROM table4 /*WHERE x=y*/)alltables
)data WHERE data.rn BETWEEN 3001 AND 3030