【发布时间】:2017-11-05 19:47:46
【问题描述】:
简介:
在查询使用UNIQUEIDENTIFIER(使用newsequentialid() 填充)作为其主键的表时,如果插入的记录具有乱序键,OFFSET / FETCH 似乎会返回不准确的结果。
我最近为 SQL Server 表实现了一个使用实体属性值模式的解决方案。我使用实体框架创建了一个数据层,用于分页数据访问。提及实体框架的唯一相关性是它负责创建我将讨论的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() 函数生成,并且与其他记录不同步。
此查询将返回所有 15 条记录,包括具有“乱序”id 的记录
SELECT *
FROM [dbo].[OptionalValues]
ORDER BY [Type]
接下来的 3 个查询对我来说没有意义。它们包括一个NOT唯一的 ORDER BY [Type],并且 NOT 包括任何明确的 [Id] 排序
此查询不显示具有“乱序”ID 的记录
SELECT *
FROM [dbo].[OptionalValues]
ORDER BY [Type]
OFFSET 0 ROWS
FETCH NEXT 10 ROWS ONLY
即使结果计数仍为 15,此查询不显示具有“乱序”ID 的记录???
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”的记录,但这些记录并未显示在查询结果中?与主键一起创建的索引是否会以任何方式影响先前查询的排序行为?
感谢您提供的任何帮助和说明。
【问题讨论】:
-
缺少order by子句,或者order by子句中指定的列包含重复值时,Sql server不保证结果的顺序。您现在看到的顺序可能会在您下次运行查询时更改。
-
ORDER BY是您表达订购要求的机制。如果您未能请求确定性排序,SQL Server 几乎不会因为不符合您的期望而出错。机制是对的,你选择忽略它。 -
另外,主键的数据类型与这个问题无关。甚至聚簇索引的数据类型也与这个问题无关。
-
@Damien_The_Unbeliever 和 Zohar-Peled - 感谢您的回复。我不明白的是,当确定性排序被删除时,在这种情况下...... SQL Server 不是“随机”对结果进行排序......它始终忽略具有 [Id] 的记录不是由 newsequentialid() 函数生成。我可以在没有确定顺序的情况下运行和重新运行查询,并始终如一地返回完全相同的结果集。如果顺序不是真正随机的,那么影响顺序的因素是什么?
-
如果您每天早上都经过一辆红色汽车,然后是一辆绿色汽车,然后是一辆蓝色汽车,这并不意味着这些司机有合同义务始终遵循相同的驾驶计划。观察到的行为不是保证行为的合适指南。
标签: sql sql-server pagination fetch offset