OFFSET FETCH意想不到的结果时,主键是UNIQUEIDENTIFIER

问题描述:

简介:
当查询使用一个UNIQUEIDENTIFIER(已使用newsequentialid())作为其主键的表,OFFSET/FETCH似乎返回不正确的结果,如果记录插入有出订单键。OFFSET FETCH意想不到的结果时,主键是UNIQUEIDENTIFIER

我最近使用实体属性值模式为SQL Server表实现了一个解决方案。我使用实体框架为分页数据访问创建了一个数据层。提及实体框架的唯一相关性是它是我将要讨论的创建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]的值为NOT由该表的newsequentialid()函数生成并且与其他记录不同步。

这个查询将返回所有15条记录,其中包括有记录的“乱序”的id

SELECT * 
FROM [dbo].[OptionalValues] 
ORDER BY [Type] 

未来3个查询是那些没有意义了我。它们包括一个ORDER BY [类型]这是独特,并做包括任何明确的[ID]订货

此查询确实有“乱序”的id

节目记录
SELECT * 
FROM [dbo].[OptionalValues] 
ORDER BY [Type] 
    OFFSET 0 ROWS 
    FETCH NEXT 10 ROWS ONLY 

此查询的确有不是显示记录有“无序”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 

我的问题确实围绕着没有真正独特排序的查询的不准确性。为什么这些查询看起来在分页行计数中识别了“超出序列号”的记录,但这些记录没有显示在查询结果中?与主键一起创建的索引是否以任何方式影响以前查询的排序行为?

感谢您提供任何帮助和澄清。

+1

当order by子句缺失或order by子句中指定的列包含重复值时,Sql server不能保证结果的顺序。您现在看到的订单现在可以在您下次运行查询时更改。 –

+0

'ORDER BY'是您表达订购要求的机制。如果您未能*请求*确定性排序,则SQL Server不会因为不符合您的期望而出错。该机制是正确的,你选择忽略它。 –

+0

此外,主键的数据类型与此问题无关。即使聚集索引的数据类型与这个问题无关。 –

当order by子句缺失或者order by子句中指定的列包含重复值时,sql server不能保证结果的顺序。这意味着行的顺序是随机的,它只是意味着它不是你可以相信是一致的东西。这是真的,顺便说一句,任何关系数据库。表格本质上是无序的。
这也是您使用offset...fetch next子句时必须指定order by子句的原因,以及为什么不能在视图,派生表或子集中使用order by而不使用topoffset...fetch next

+0

做出以下声明是否正确: – MarcusTheShogun

+0

确定性==不是随机 非确定性!=随机(不一定等于) 我认为后者是令我困惑的东西。我一直在运行非确定性查询,期望我能“看到”不同的结果,因为SQL Server不能保证结果的顺序。正如@Damien_The_Unbeliever所述......“观察到的行为并不适合作为保证行为的指导”......这使我相信,我期望观察不同的结果是不协调的。 – MarcusTheShogun

+0

是的,这是正确的。 –