回答:
の使用は避けSELECT *ます。すべての列であっても、実際に必要な列を指定します。
SQL Server 2005以降
SELECT col1, col2
FROM (
SELECT col1, col2, ROW_NUMBER() OVER (ORDER BY ID) AS RowNum
FROM MyTable
) AS MyDerivedTable
WHERE MyDerivedTable.RowNum BETWEEN @startRow AND @endRow
SQL Server 2000
SELECT *は、テーブルの構造が変わってもクエリは実行されますが、結果は異なります。列が追加された場合、これは便利な場合があります(ただし、どこかで名前を付けて使用する必要があります)。列が削除または名前変更された場合、変数が初期化されていないために奇妙な動作をするコードよりも、SQLが目に見える形で壊れる方が良いです。
すべてのページを順番に処理する場合は、前のページに表示された最後のキー値を覚えておいて、TOP (25) ... WHERE Key > @last_key ORDER BY Keyこれを効率的に検索できる適切なインデックスが存在する場合に使用するのが最も効果的な方法です。APIカーソルがない場合は。
arbitaryページにSQL Server 2005の最適なソリューションを選択するための- 2008 R2は、おそらくあるROW_NUMBERとBETWEEN
SQL Server 2012+の場合、このニーズのために拡張されたORDER BY句を使用できます。
SELECT *
FROM MyTable
ORDER BY OrderingColumn ASC
OFFSET 50 ROWS
FETCH NEXT 25 ROWS ONLY
これは一方向です(SQL2000)
SELECT * FROM
(
SELECT TOP (@pageSize) * FROM
(
SELECT TOP (@pageNumber * @pageSize) *
FROM tableName
ORDER BY columnName ASC
) AS t1
ORDER BY columnName DESC
) AS t2
ORDER BY columnName ASC
これは別の方法です(SQL 2005)
;WITH results AS (
SELECT
rowNo = ROW_NUMBER() OVER( ORDER BY columnName ASC )
, *
FROM tableName
)
SELECT *
FROM results
WHERE rowNo between (@pageNumber-1)*@pageSize+1 and @pageNumber*@pageSize
あるOFFSET .. FETCHSQL Serverの2012年に、しかし、あなたは指定する必要がありますORDER BY列を。
ORDER BY(他の人が示唆しているように)列として渡すことができる明示的な列が本当にない場合は、このトリックを使用できます:
SELECT * FROM MyTable
ORDER BY @@VERSION
OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY
...または
SELECT * FROM MyTable
ORDER BY (SELECT 0)
OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY
ユーザーが順序を明示的に指定しない場合は、jOOQで使用しています。これにより、追加コストなしでかなりランダムな順序が生成されます。
より多くの大きなデータ列を持つテーブルの場合、私は次のようにします。
SELECT
tablename.col1,
tablename.col2,
tablename.col3,
...
FROM
(
(
SELECT
col1
FROM
(
SELECT col1, ROW_NUMBER() OVER (ORDER BY col1 ASC) AS RowNum
FROM tablename
WHERE ([CONDITION])
)
AS T1 WHERE T1.RowNum BETWEEN [OFFSET] AND [OFFSET + LIMIT]
)
AS T2 INNER JOIN tablename ON T2.col1=tablename.col1
);
-
[CONDITION] can contain any WHERE clause for searching.
[OFFSET] specifies the start,
[LIMIT] the maximum results.
ROW_NUMBER関数は1つの列のみを参照する必要があり、一致する行のみがすべての列で返されるため、BLOBなどの大きなデータを含むテーブルでのパフォーマンスが大幅に向上します。
ページネーションの私の選択を参照してください
SELECT TOP @limit * FROM (
SELECT ROW_NUMBER() OVER (ORDER BY colunx ASC) offset, * FROM (
-- YOU SELECT HERE
SELECT * FROM mytable
) myquery
) paginator
WHERE offset > @offset
これはページネーションを解決します;)
バージョンによっては、直接実行することはできませんが、次のようなハックを行うことができます
select top 25 *
from (
select top 75 *
from table
order by field asc
) a
order by field desc
ここで、「フィールド」はキーです。
以下は、SQL Server 2012で動作する最初の50レコードを除く25レコードを表示します。
SELECT * FROM MyTable ORDER BY ID OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY;
あなたはあなたの要件としてIDを置き換えることができます
ROW_NUMBER() OVER (ORDER BY)パフォーマンスが非常に低いため、ステートメントを使用するときは注意が必要です。同じことが、共通テーブル式を使用するROW_NUMBER()場合にも当てはまります。次のスニペットを使用していますが、ID付きのテーブル変数を使用してページ番号を提供するよりも少し高速であることが証明されています。
DECLARE @Offset INT = 120000
DECLARE @Limit INT = 10
DECLARE @ROWCOUNT INT = @Offset+@Limit
SET ROWCOUNT @ROWCOUNT
SELECT * FROM MyTable INTO #ResultSet
WHERE MyTable.Type = 1
SELECT * FROM
(
SELECT *, ROW_NUMBER() OVER(ORDER BY SortConst ASC) As RowNumber FROM
(
SELECT *, 1 As SortConst FROM #ResultSet
) AS ResultSet
) AS Page
WHERE RowNumber BETWEEN @Offset AND @ROWCOUNT
DROP TABLE #ResultSet
私はこのテクニックをページ分割に使用しています。すべての行をフェッチするわけではありません。たとえば、ページに上位100行を表示する必要がある場合、100のwhere句のみをフェッチします。SQLの出力には一意のキーが必要です。
テーブルには以下が含まれます。
ID, KeyId, Rank
同じランクが複数のKeyIdに割り当てられます。
SQLは select top 2 * from Table1 where Rank >= @Rank and ID > @Id
初めて、両方に0を渡します。2回目のパス1および14。3回目のパス2および6 ....
10番目のレコードのランクとIDの値が次のレコードに渡されます
11 21 1
14 22 1
7 11 1
6 19 2
12 31 2
13 18 2
これにより、システムへのストレスが最小になります
SqlServer2005では、次のことができます。
DECLARE @Limit INT
DECLARE @Offset INT
SET @Offset = 120000
SET @Limit = 10
SELECT
*
FROM
(
SELECT
row_number()
OVER
(ORDER BY column) AS rownum, column2, column3, .... columnX
FROM
table
) AS A
WHERE
A.rownum BETWEEN (@Offset) AND (@Offset + @Limit-1)
@Offset + @Limit - 1?@Limitが10の場合、これは11行を返します。
レコードを注文する時間を無駄にすることなくそれを行う最良の方法は次のとおりです。
select 0 as tmp,Column1 from Table1 Order by tmp OFFSET 5000000 ROWS FETCH NEXT 50 ROWS ONLY
1秒もかかりません!
大きなテーブルに最適なソリューション。
私はしばらくの間この回答を検索してきましたが(一般的なクエリの場合)、SQL Server 2000+でROWCOUNTとカーソルを使用し、TOPまたは一時テーブルなしでそれを行う別の方法を見つけました。
SET ROWCOUNT [OFFSET+LIMIT]結果を制限することができ、カーソルを使用して、目的の行に直接移動し、最後までループします。
したがって、クエリは次のようになります。
SET ROWCOUNT 75 -- (50 + 25)
DECLARE MyCursor SCROLL CURSOR FOR SELECT * FROM pessoas
OPEN MyCursor
FETCH ABSOLUTE 50 FROM MyCursor -- OFFSET
WHILE @@FETCH_STATUS = 0 BEGIN
FETCH next FROM MyCursor
END
CLOSE MyCursor
DEALLOCATE MyCursor
SET ROWCOUNT 0
SQL Server 2012(11.x)以降とAzure SQL Databaseでは、 "fetch_row_count_expression"を使用できます。これと共に、ORDER BY句も使用できます。
USE AdventureWorks2012;
GO
-- Specifying variables for OFFSET and FETCH values
DECLARE @skip int = 0 , @take int = 8;
SELECT DepartmentID, Name, GroupName
FROM HumanResources.Department
ORDER BY DepartmentID ASC
OFFSET @skip ROWS
FETCH NEXT @take ROWS ONLY;
Note OFFSET クエリ式から行を返し始める前にスキップする行数を指定します。開始行番号ではありません。したがって、最初のレコードを含めるには0にする必要があります。