4

SQL Server 2008 でページングを実装するより効率的な方法を探しています。

@from から @to までの結果セット行をスコア値順に取得する必要がありますが、特定の @from および @to 行のスコア値と一致する @from および @to の直前と直後のすべての行も取得する必要があります。たとえば、これは次の 2 つのクエリのいずれかのようになります。

注意: スコア値は一意ではなく、インデックス化されておらず、事前に並べ替えられた形式でクエリの残りの部分に提供されていません。

a) (実際には、この最初の例で必要な結果が得られるとは限りません。なぜなら、2 つのサブクエリの 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  

次のテスト CTE と組み合わせて構文 (b) を使用して、必要な結果を取得します。

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 つの遅延スプール演算子が必要です。これのためのより効率的な構文はありますか?

現在の実際の実行計画は次のとおりです。 ここに画像の説明を入力

4

1 に答える 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
于 2013-02-06T05:43:07.963 に答える