OFFSET ... FETCH
SQL Server 2012 引入的新模型提供了简单且快速的分页。考虑到这两种形式在语义上相同且非常常见,为什么会有任何差异?
人们会假设优化器可以识别两者并将它们(简单地)优化到最大程度。
这是一个非常简单的案例,OFFSET ... FETCH
根据成本估算,速度提高了约 2 倍。
SELECT * INTO #objects FROM sys.objects
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY object_id) r
FROM #objects
) x
WHERE r >= 30 AND r < (30 + 10)
ORDER BY object_id
SELECT *
FROM #objects
ORDER BY object_id
OFFSET 30 ROWS FETCH NEXT 10 ROWS ONLY
Run Code Online (Sandbox Code Playgroud)
可以通过创建 CIobject_id
或添加过滤器来改变此测试用例,但不可能消除所有计划差异。OFFSET ... FETCH
总是更快,因为它在执行时做的工作更少。
sql-server optimization execution-plan sql-server-2012 offset-fetch
从 2012 年开始,SQL Server 文档显示他们支持OFFSET..FETCH
我尝试使用的而不是LIMIT
.
以下在 PostgreSQL 中可以很好地对结果集进行采样,
SELECT *
FROM ( VALUES (1),(2),(3) ) AS t(x)
OFFSET 0 ROWS
FETCH NEXT 1 ROWS ONLY;
Run Code Online (Sandbox Code Playgroud)
但是,使用 SQL Server,我得到
Msg 153, Level 15, State 2, Line 4
Invalid usage of the option FIRST in the FETCH statement.
Run Code Online (Sandbox Code Playgroud)
这里发生了什么?SQL Server 是否支持标准化的OFFSET
.. FETCH
?
表jtest
有 200k 行,每行包含 jsonb { id: "<uuid>", key: <index> }
(<index>
每行递增 1-200k 的整数)。上还有btree索引data->'key'
。
create extension if not exists pgcrypto;
create table jtest (data jsonb not null default '{}');
insert into jtest (data)
select json_build_object('id', gen_random_uuid(), 'key', i)::jsonb
FROM generate_series(1,200000) i;
create index jtest_key on jtest ((data->'key'));
Run Code Online (Sandbox Code Playgroud)
第一个查询(快速):
EXPLAIN ANALYZE
select j.data
from jtest j
order by j.data->'key'
limit 20;
-- "Limit (cost=0.42..1.43 rows=20 width=74) (actual time=0.023..0.044 rows=20 loops=1)"
-- " -> Index Scan using …
Run Code Online (Sandbox Code Playgroud) 使用时OFFSET ... FETCH
,我得到了……有趣的结果。
这里有两个 sqlfiddles 来说明我的问题。
http://sqlfiddle.com/#!6/71ac1/4和http://sqlfiddle.com/#!6/71ac1/8
第一个小提琴是第一页,而第二个是...第二页。
这是未分页的结果。
首先,分页结果与未分页结果的顺序不同。我想我对此很酷,因为无论如何我都不会显示未分页的结果。
但是,尽管我指定的偏移量为 0,但由于某种原因,它决定将它们按输入的相反顺序放置,但它跳过了前 3 个。
在第二页上,我看到了出现在第一页上的结果。
尽管在本示例中是人为设计的,但它们都具有相同的值这一事实在我在现实生活中处理的特定查询中是现实的。这是一个表格,用户选择按 排序date
。
在研究不同的查询计划以提高性能时,我注意到 FETCH 正在隐式转换为bigint
.
示例表和查询:
CREATE TABLE checkPagintion
(
Id INT NOT NULL PRIMARY KEY CLUSTERED,
Name NVARCHAR(100)
)
DECLARE @paramPageNumber AS INT,
@paramPageSize AS INT;
SELECT *
FROM checkPagintion
ORDER BY Id
OFFSET @paramPageNumber ROWS
FETCH NEXT @paramPageSize ROWS ONLY
Run Code Online (Sandbox Code Playgroud)
此查询的执行计划:
我的问题:我应该对所有分页查询使用 bigint 吗?如果我使用 int 会不会有问题,因为implict_conversion 以性能低下着称?
sql-server type-conversion offset-fetch paging sql-server-2014
目前,我有一个base_voter
包含大约 100M 虚拟数据的数据表。我有如下存储过程:
CREATE Procedure [dbo].[spTestingBaseVoter]
@SortColumn NVARCHAR(128) = N'name_voter',
@SortDirection VARCHAR(4) = 'asc',
@offset INT,
@limit INT
As
Begin
SET NOCOUNT ON;
-- reject any invalid sort directions:
IF LOWER(@SortDirection) NOT IN ('asc','desc')
BEGIN
RAISERROR('Invalid parameter for @SortDirection: %s', 11, 1, @SortDirection);
RETURN -1;
END
-- reject any unexpected column names:
IF LOWER(@SortColumn) NOT IN (N'name_voter', N'home_street_address_1', N'home_address_city')
BEGIN
RAISERROR('Invalid parameter for @SortColumn: %s', 11, 1, @SortColumn);
RETURN -1;
END
--SET @SortColumn = QUOTENAME(@SortColumn);
DECLARE @sql NVARCHAR(MAX); …
Run Code Online (Sandbox Code Playgroud) performance sql-server offset-fetch paging query-performance
FETCH FIRST
PostgreSQL和PostgreSQL之间有什么区别FETCH NEXT
?文档只是说
NEXT 获取下一行
FIRST 获取查询的第一行
这没什么解释。我创建了一个包含示例行的示例表,并执行
SELECT * from users
FETCH FIRST 2 ROWS ONLY;
Run Code Online (Sandbox Code Playgroud)
SELECT * from users
FETCH NEXT 2 ROWS ONLY;
Run Code Online (Sandbox Code Playgroud)
并得到完全相同的输出。它几乎就像 ifFETCH FIRST
和FETCH NEXT
只是同义词LIMIT
(我读到,它不是 SQL 标准的一部分,与 不同FETCH [FIRST|NEXT]
)
如果两者相同,为什么文档不这么说?还是毕竟存在一些差异?
这个 Stack Overflow 答案意味着它们至少在某些 RDBMS 中可能以相同的方式运行,特别是在 MS Server 中
offset-fetch ×7
sql-server ×5
paging ×2
postgresql ×2
limits ×1
optimization ×1
performance ×1