当 PRIMARY KEY 为 UNIQUEIDENTIFIER 时,OFFSET FETCH 出现意外结果

OFFSET FETCH unexpected results when PRIMARY KEY is UNIQUEIDENTIFIER

剧情简介:
当查询使用 UNIQUEIDENTIFIER(使用 newsequentialid() 填充)作为其主键的 table 时,如果插入的记录具有 OFFSET / FETCH 似乎 return 不准确的结果乱序键。

我最近为 SQL 服务器 table 使用实体属性值模式实施了一个解决方案。我创建了一个数据层,利用 Entity Framework 进行分页数据访问。提及 Entity Framework 的唯一相关性是它负责创建我将要讨论的 OFFSET / FETCH SQL 语句。我知道可以在不使用 OFFSET / FETCH 的情况下实施的替代解决方案,但是,这不是我的 post 的意图。此 post 的目的是准确了解 OFFSET / FETCH 查询发生了什么。

我包含了重现此问题所需的 SQL。

以下 SQL 语句将创建一个实现 EAV 模式的 Table:

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]

以下语句将测试数据插入table:

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] 值 不是 由 table 的 newsequentialid() 函数生成的并且与其他记录。

此查询将 return 所有 15 条记录,包括具有 "out of sequence" ID 的记录

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

接下来的 3 个查询对我来说没有意义。它们包括 NOT 唯一的 ORDER BY [Type],并且 NOT 包括任何明确的 [Id] 排序

此查询 显示具有 "out of sequence" ID 的记录

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

此查询 NOT 显示具有 "out of sequence" ID 的记录,即使结果计数仍然是 15???

SELECT * 
FROM [dbo].[OptionalValues] 
ORDER BY [Type] 
    OFFSET 10 ROWS 
    FETCH NEXT 10 ROWS ONLY

此查询显示所有 15 条记录,包括具有 "out of sequence" 个 ID 的行

SELECT * 
FROM [dbo].[OptionalValues] 
ORDER BY [Type] 
    OFFSET 0 ROWS 
    FETCH NEXT 15 ROWS ONLY

"fix"是使用[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

我的问题实际上围绕着没有真正唯一排序的查询的不准确性。为什么查询看似识别了分页行数中带有 "out of sequence id" 的记录,但这些记录未显示在查询结果中?与主键一起创建的索引是否以任何方式影响先前查询的排序行为?

感谢您提供的任何帮助和说明。

Sql 如果缺少 order by 子句,或者当 order by 子句中指定的列包含重复值时,服务器不保证结果的顺序。这 并不 意味着行的顺序是随机的,它只是意味着你不能相信它是一致的。顺便说一句,对于任何关系数据库都是如此。表格本质上是无序的。
这也是为什么在使用 offset...fetch next 子句时必须指定 order by 子句的原因,以及为什么不能在视图、派生表或 cte 中使用 order by 而不使用 topoffset...fetch next