SQL Server 顶部,顶部和底部均有连接

问题描述 投票:0回答:1

我正在寻找一种更有效的方法来在 sql server 2008 中实现分页。

我需要检索结果集行@from到@to,按分值排序,但我还需要检索@from和@to之前和之后与这些特定@from和@to行的分值匹配的所有行。例如,这可能类似于以下两个查询之一:

注意,分值不是唯一的,没有索引,并且不会以预排序的形式提供给查询的其余部分。

a)(实际上,我认为第一个示例不能保证给出我需要的结果,因为我认为两个子查询中的 order by 不能保证产生相同的排序。但是为了理解我希望查询语法做什么,仅考虑此示例子查询中的 order-by 是相同的)

select *  
from (  
    select top (@to) * with ties  
    from result_set  
    order by score desc  
)  tt  
union  
select  
from (  
    select top (@to - @from + 1) * with ties  
    from (  
        select top (@to) *  
        result_set
        order by score desc  
    ) tt  
    order by score asc  
)  tt
order by score desc

b)

/*EDIT: nested the rank() window function and related where criteria one level deeper than
the count(*), as this gave me significant (25%) decrease in runtime with my data, and just  
kinda makes sense.*/  

select score  
from (  
    select  
        score,  
        myrank,  
        count(*) over (partition by score) frequency  
    from (
        select  
            score,  
            rank() over (order by score desc) myrank
        from result_set  
    ) tt
    where myrank <= @to
) tt  
where @from <= myrank + frequency - 1  
order by score desc  

我使用语法 (b) 结合以下测试 CTE 获得了所需的结果:

with result_set (score) as (
    select 0.5 union all
    select 0.5 union all
    select 0.2 union all
    select 0.1 union all
    select 0.55 union all
    select 0.5 union all
    select 0.1
)

但是分区窗口函数需要 2 个嵌套循环和 3 个惰性假脱机运算符。有更有效的语法吗?

以下是当前实际的执行计划: enter image description here

t-sql sql-server-2008 pagination query-optimization
1个回答
0
投票

您可以先获取底部值。然后使用顶部关系进行常规分页,但包含等于底部值的值:

DECLARE @pageSize int = @to - @from + 1

DECLARE @bottomValue <datatype> = 
(
     SELECT MIN(score)
     FROM 
     (
          SELECT TOP(@from) score
          FROM <TABLENAME>
          ORDER BY score DESC
     )
)

SET @from = @from - 1

SELECT TOP (@pageSize) * WITH TIES --TopTies
FROM <TABLENAME>
WHERE <COLUMN_ID> NOT IN
                (
                                SELECT TOP (@from) <COLUMN_ID>
                                FROM <TABLENAME>
                                ORDER BY score DESC
                )
ORDER BY score DESC

UNION

SELECT *
FROM <TABLENAME>
WHERE score = @bottomValue --BottomTies

使用此查询的好处是,对于第一页,您将获得更快的响应时间(更少的读取)。缺点是随着 @from 的增加,读取次数也会增加。但是,我认为如果使用 row_number 或rank 这样的函数,则无论是第一页还是最后一页,都必须评估所有表数据。

另一种方法,不确定是否最适合您的情况,是将最后一个值发送到 sp:

--Parameter
@lastScore <datatype> = null


--Logic

SELECT TOP(@to) * WITH TIES
FROM [TABLENAME]
WHERE score < @lastScore OR @lastScore IS NULL -- opt1
--WHERE score <= @lastScore OR @lastScore IS NULL opt2
ORDER BY score DESC
© www.soinside.com 2019 - 2024. All rights reserved.