10

200 万を超えるレコードを含むデータベースがあり、Web アプリケーションに表示するためにページネーションを実行する必要がありますDataGrid

私はすでに を使用しようとしましROW_NUMBER()たが、この方法では 200 万件のレコードがすべて選択され、10 件のレコードしか取得されません。も使用TOP 10しようとしましたが、ページを制御するには最初と最後の ID を保存する必要があります。そして、使用DataAdapter.Fill()するとすべてのコンテンツが選択され、必要な 10 個のレコードが取得されることを読みました。

最良の方法はどれですか?使用する必要がありますDataAdapter.Fill()か? または、SQL Server の機能を使用しますROW_NUMBER()か? または使用してみてくださいTOP 10

4

3 に答える 3

5
ALTER PROCEDURE [dbo].[SP_tblTest_SelectSpecificRecordsWithCTE]
    @FromRow int = 1000000,
    @PgSize int = 10
AS
BEGIN
    ;WITH RecordsRN AS
    (
        select ID, colValue, ROW_NUMBER() over(order by colvalue) as Num from tblTest
    )
    SELECT ID Value, colValue Text FROM RecordsRN WHERE Num between @FromRow AND (@FromRow+@PgSize-1)
END

これは、ページングに使用しているクエリです。それを使用すると、uは4〜5秒で必要な10レコードを取得します。私は3秒で10レコードを取得しており、データベース内の合計レコードは1,000万です。トップ10を使用しないでください。毎回、同じ10レコードしか取得されません。私の場合、セッションでページサイズと開始行番号(@FromRow)を維持しており、これら2つの値を以下のストアドプロシージャに渡して結果を取得します。さらに、SQL 2012を使用している場合は、OFFSETを使用して次の10行をフェッチすることをお勧めします。オフセットキーワードについてグーグルで検索すると、あなたは一番上にあなたの望む結果を見るでしょう。

ありがとう

于 2013-01-17T10:45:33.890 に答える
2

ROW_NUMBER()(私のコードのように)静的ユーティリティ関数を使用して実装します。この関数GetPaginatedSQLは、元のSQLクエリを制限付き/ページ分割されたクエリに自動的にラップします。

これは私が使用するものです:

namespace Persistence.Utils
{
    public class SQLUtils
    {
        /// <summary>
        /// Builds a paginated/limited query from a SELECT SQL.
        /// </summary>
        /// <param name="startRow">Start row</param>
        /// <param name="numberOfRows">Number/quatity of rows to be expected</param>
        /// <param name="sql">Original SQL (without its ordering clause)</param>
        /// <param name="orderingClause">MANDATORY: ordering clause (including ORDER BY keywords)</param>
        /// <returns>Paginated SQL ready to be executed.</returns>
        /// <remarks>SELECT keyword of original SQL must be placed exactly at the beginning of the SQL.</remarks>
        public static string GetPaginatedSQL(int startRow, int numberOfRows, string sql, string orderingClause)
        {
            // Ordering clause is mandatory!
            if (String.IsNullOrEmpty(orderingClause))
                throw new ArgumentNullException("orderingClause");

            // numberOfRows here is checked of disable building paginated/limited query
            // in case is not greater than 0. In this case we simply return the
            // query with its ordering clause appended to it. 
            // If ordering is not spe
            if (numberOfRows <= 0)
            {
                return String.Format("{0} {1}", sql, orderingClause);
            }
            // Extract the SELECT from the beginning.
            String partialSQL = sql.Remove(0, "SELECT ".Length);

            // Build the limited query...
            return String.Format(
                "SELECT * FROM ( SELECT ROW_NUMBER() OVER ({0}) AS rn, {1} ) AS SUB WHERE rn > {2} AND rn <= {3}",
                orderingClause,
                partialSQL,
                startRow.ToString(),
                (startRow + numberOfRows).ToString()
            );
        }
    }
}

上記の機能は改善される可能性がありますが、初期の実装です。

次に、DAOで、次のようなものを作成する必要があります。

using (var conn = new SqlConnection(CONNECTION_STRING))
{
    using (var cmd = conn.CreateCommand())
    {
        String SQL = "SELECT * FROM MILLIONS_RECORDS_TABLE";
        String SQLOrderBy = "ORDER BY DATE ASC "; //GetOrderByClause(Object someInputParams);
        String limitedSQL = GetPaginatedSQL(0, 50, SQL, SQLOrderBy);

        DataSet ds = new DataSet();
        SqlDataAdapter adapter = new SqlDataAdapter();

        cmd.CommandText = limitedSQL;

        // Add named parameters here to the command if needed...

        adapter.SelectCommand = cmd;
        adapter.Fill(ds);

        // Process the dataset...
    }
    conn.Close();
}

それが役に立てば幸い。

于 2013-01-17T14:35:31.647 に答える
1

次のパターンを使用して、ページングされたサブクエリを(自動的に)生成します。

select top (@takeN) <your-column-list>
from (
    select qSub2.*, _row=row_number() over (order by SomeColumn Asc, SomethingElse Desc)
    from (
        select top (@takeN + @skipN) <your-column-list> 
        from ( 
            select <your-subquery-here>
        ) as qSub1 
        order by SomeColumn Asc, SomethingElse Desc
    ) as qSub2
) qSub3
where _row > @skipN
order by _row

このパターンに関する注意:

  • サブクエリは、概念的@skipNに行をスキップしてから次の@takeN行を取得します。
  • 結果の余分な列を気にしない場合は、;_rowに置き換えることができます。明示的な列リストを使用するのは、実行時に列のセットをサブセット化できるためです。これは、たとえば、主キー列のみを検索する場合などに役立ちます。<your-column-list>*
  • 条項order byは同一である必要があります。SQLサーバーのオプトマイザーは一般的にそれを理解するのに十分賢いです。top重複は、結果を切り捨てるために使用される句の副作用です。topソートされていないサブクエリでは合法ではありません。また、topは、クエリオプティマイザがこのクエリが数行を返す可能性があることを理解するのに役立ちます。
  • @takeNページ番号+サイズベースのパラメータと @skipNは対照的に、使用する理由はかなりマイナーです。第一に、クエリではもう少し柔軟性があり、少し単純です。第二に、SQLサーバーの長所を少しよく発揮します。DBは、そもそもこの種のクエリの最適化について特に優れているわけではありません。このような外側の単純なtop句を使用すると、オプティマイザが可能な最大行数を理解するのは簡単です。一般に、オプティマイザーを混乱させる傾向があるため、SQLでの計算は避けようとします(ただし、@ pagecount * @ pagesizeの実験では、大きな問題ではないことが示されています)。

SQL Server 2012は、はるかに単純なこのシナリオの新しいoffset...fetch句をサポートしていることに注意してください。

于 2013-01-17T12:11:10.167 に答える