7

以下は、オブジェクトのページリストを返すために使用しているコードです。

string query2 = @"
        select count(*) as TotalCount from blogposts p where p.Deleted = 0 and p.PublishDate <= @date
        select * from (
            select p.*, 
            row_number() over(order by publishdate desc) as rownum
            from blogposts as p
            where p.Deleted = 0 and p.PublishDate <= @date
        ) seq
        where seq.rownum between @x and @y";

using (var cn = new SqlConnection(connectionString))
{
    cn.Open();
    using (var multi = cn.QueryMultiple(query2, new { x= lower, y = upper, date = DateTime.UtcNow }))
    {
        var totalCount = multi.Read<int>().Single();
        var posts = multi.Read<PostModel>().ToList();
        return new PagedList<PostModel>(posts, page, pageSize, x => totalCount);
    }
}

これは機能しますが、基準を2回定義する必要があることを意味します。1回はカウントクエリ用、もう1回は結果セットクエリ用です。文字列の連結に頼るのではなく、1つのクエリだけを実行できます。

        string query = @"
                select * from (select p.*, 
                row_number() over(order by publishdate desc) as rownum,
                count(*) over() as TotalCount
                from blogposts as p) seq
                where seq.rownum between @x and @y";

ただし、Dapperを使用してこれをマッピングすることはできないようです。複数の結果がないため、上記と同じ方法を使用することはできません。マルチマッピングを使用してみましたが、これはIEnumerableを返すことを期待しています。

以下にどのようにマッピングしますか?

    public class PostList
    {
        public IEnumerable<PostModel> Posts;
        public int TotalCount { get; set; }
    }

ありがとう

ベン

4

1 に答える 1

6

ええと...あなたはしません...

TotalCountプロパティを含めるようにPostModelを修正する必要があります...これは本当に醜いです。または、ダイナミックを実行して、Selectこれも醜いで再マップします。

ご覧のとおり、count(*)をN回返していcount(*) over()ます...これはハックです。このハックを使用すると、必ずしも高速になるとは限りません。select count(*)一部のシナリオでは、ダブルクエリを実行するよりも遅いと測定しました。特に、すべての列を選択しているわけではないため、一部のインデックスをショートカットできます。さらに、ハックは特定のページングの最適化を無効にします。たとえばselect top N、クエリに追加することはできません。

ページングクエリに関する私の推奨事項は、インデックスを正しく作成することです。これが重要です。パフォーマンスを測定し、このハックが実際に役立つかどうかを確認します(正しいインデックスが設定されている場合)。

文字列の連結に関する懸念事項については説明しますが、そのための一般的なヘルパーメソッドはいつでも定義できます。

于 2011-06-02T12:26:13.587 に答える