梗概:
查询使用UNIQUEIDENTIFIER
(使用newsequentialid()
填充)作为其主键的表时,如果插入了具有乱序键的记录,OFFSET / FETCH
似乎会返回不准确的结果。
我最近使用SQL Server表的实体属性值模式实现了一个解决方案。我创建了一个利用Entity Framework进行分页数据访问的数据层。提到实体框架的唯一相关性是它负责创建我将要讨论的OFFSET / FETCH
SQL语句。我知道可以实现的替代解决方案在不使用OFFSET / FETCH
的情况下工作,但是,这不是我的帖子的意图。这篇文章的目的是准确理解OFFSET / FETCH
查询发生了什么。
我包含了复制此问题所需的必要SQL。
以下SQL语句将创建一个实现EAV模式的表:
CREATE TABLE [dbo].[OptionalValues]
(
[Id] [uniqueidentifier] NOT NULL
CONSTRAINT [DF_OptionalValues_Id] DEFAULT (newsequentialid()),
[Type] [nvarchar](450) NOT NULL,
[Name] [nvarchar](450) NOT NULL,
[Value] [nvarchar](450) NOT NULL,
CONSTRAINT [PK_OptionalValues]
PRIMARY KEY CLUSTERED ([Id] ASC)
) ON [PRIMARY]
以下语句将测试数据插入表中:
INSERT [dbo].[OptionalValues] ([Id], [Type], [Name], [Value])
VALUES (N'04c9f78a-5114-e711-90c2-005056a9316b', N'TargetOrgans', N'Eyes', N'Eyes');
INSERT [dbo].[OptionalValues] ([Id], [Type], [Name], [Value])
VALUES (N'05c9f78a-5114-e711-90c2-005056a9316b', N'TargetOrgans', N'Skin', N'Skin');
INSERT [dbo].[OptionalValues] ([Id], [Type], [Name], [Value])
VALUES (N'06c9f78a-5114-e711-90c2-005056a9316b', N'TargetOrgans', N'Autonomic Nervous System', N'Autonomic Nervous System');
INSERT [dbo].[OptionalValues] ([Id], [Type], [Name], [Value])
VALUES (N'07c9f78a-5114-e711-90c2-005056a9316b', N'TargetOrgans', N'Kidneys', N'Kidneys');
INSERT [dbo].[OptionalValues] ([Id], [Type], [Name], [Value])
VALUES (N'08c9f78a-5114-e711-90c2-005056a9316b', N'TargetOrgans', N'Liver', N'Liver');
INSERT [dbo].[OptionalValues] ([Id], [Type], [Name], [Value])
VALUES (N'09c9f78a-5114-e711-90c2-005056a9316b', N'TargetOrgans', N'Respiratory System', N'Respiratory System');
INSERT [dbo].[OptionalValues] ([Id], [Type], [Name], [Value])
VALUES (N'0ac9f78a-5114-e711-90c2-005056a9316b', N'TargetOrgans', N'Lungs', N'Lungs');
INSERT [dbo].[OptionalValues] ([Id], [Type], [Name], [Value])
VALUES (N'0bc9f78a-5114-e711-90c2-005056a9316b', N'TargetOrgans', N'Central Nervous System', N'Central Nervous System');
INSERT [dbo].[OptionalValues] ([Id], [Type], [Name], [Value])
VALUES (N'0cc9f78a-5114-e711-90c2-005056a9316b', N'TargetOrgans', N'Blood', N'Blood');
INSERT [dbo].[OptionalValues] ([Id], [Type], [Name], [Value])
VALUES (N'0dc9f78a-5114-e711-90c2-005056a9316b', N'TargetOrgans', N'Heart', N'Heart');
INSERT [dbo].[OptionalValues] ([Id], [Type], [Name], [Value])
VALUES (N'0ec9f78a-5114-e711-90c2-005056a9316b', N'TargetOrgans', N'Reproductive System', N'Reproductive System');
INSERT [dbo].[OptionalValues] ([Id], [Type], [Name], [Value])
VALUES (N'0fc9f78a-5114-e711-90c2-005056a9316b', N'TargetOrgans', N'Cardiovascular System', N'Cardiovascular System');
INSERT [dbo].[OptionalValues] ([Id], [Type], [Name], [Value])
VALUES (N'd6fdf6b9-6014-e711-815c-080027f9bf3f', N'TargetOrgans', N'TEST_ONE', N'TEST_ONE');
INSERT [dbo].[OptionalValues] ([Id], [Type], [Name], [Value])
VALUES (N'5a8c5533-6114-e711-815c-080027f9bf3f', N'TargetOrgans', N'TEST_TWO', N'TEST_TWO')
INSERT [dbo].[OptionalValues] ([Id], [Type], [Name], [Value])
VALUES (N'801a12da-6214-e711-815c-080027f9bf3f', N'TargetOrgans', N'TEST_THREE', N'TEST_THREE');
插入的最后三个记录的[Id]值由表newsequentialid()
函数生成 NOT ,并且与其他记录不同步。
此查询将返回所有15条记录,包括具有“无序”ID
的记录SELECT *
FROM [dbo].[OptionalValues]
ORDER BY [Type]
接下来的3个查询是对我没有意义的查询。它们包括ORDER BY [Type] NOT 唯一,并且 NOT 包含任何显式[Id]排序
此查询执行 NOT 显示具有“无序”ID的记录
SELECT *
FROM [dbo].[OptionalValues]
ORDER BY [Type]
OFFSET 0 ROWS
FETCH NEXT 10 ROWS ONLY
此查询 NOT 显示具有“无序”ID的记录,即使结果计数仍为15 ???
SELECT *
FROM [dbo].[OptionalValues]
ORDER BY [Type]
OFFSET 10 ROWS
FETCH NEXT 10 ROWS ONLY
此查询显示所有15条记录,包括具有“无序”ID
的行SELECT *
FROM [dbo].[OptionalValues]
ORDER BY [Type]
OFFSET 0 ROWS
FETCH NEXT 15 ROWS ONLY
“修复”是使用[Id]列添加真正独特的排序。
SELECT *
FROM [dbo].[OptionalValues]
ORDER BY [Type], [Id]
OFFSET 0 ROWS
FETCH NEXT 10 ROWS ONLY
SELECT *
FROM [dbo].[OptionalValues]
ORDER BY [Type], [Id]
OFFSET 10 ROWS
FETCH NEXT 10 ROWS ONLY
我的问题实际上围绕着没有真正独特排序的查询的不准确性。为什么查询似乎在分页行计数中识别出具有“无序ID”的记录,但这些记录未显示在查询结果中?与主键一起创建的索引是否会以任何方式影响先前查询的排序行为?
感谢您提供的任何帮助和说明。
答案 0 :(得分:1)
当缺少order by子句时,或者order by子句中指定的列包含重复值时,SQL Server不保证结果的顺序。这个不意味着行的顺序是随机的,这只意味着它不是你可以信任的东西是一致的。对于任何关系数据库来说都是如此。桌子本质上没有订购。
这也是您在使用order by
子句时必须指定offset...fetch next
子句的原因,以及为什么在视图,派生表或不使用{cte时不能使用order by
的原因{1}}或top
。