我目前正在开发一个在Microsoft SQL Server上保存数据的应用程序。在测试时我注意到在一个表中,行看似随机排序,而在所有其他表中,它们按主键排序,这是一个自动递增的整数。
示例:
有序表:
随机顺序:
我知道我可以在SQL查询中对它们进行排序,所以这不是我的问题。
我的问题:为什么他们的订购方式有所不同?
编辑:有人想查看CREATE TABLE
语句
有序表:
CREATE TABLE [dbo].[Label](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](255) NOT NULL,
[XmlTemplatePath] [nvarchar](255) NOT NULL,
CONSTRAINT [PK_Label] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [UNIQUE_Label_XmlTemplatePath] UNIQUE NONCLUSTERED
(
[XmlTemplatePath] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
无序表:
CREATE TABLE [dbo].[Parameter](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](255) NOT NULL,
CONSTRAINT [PK_Parameter] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [UNIQUE_Parameter_Name] UNIQUE NONCLUSTERED
(
[Name] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
答案 0 :(得分:2)
SQL Server通常努力尽可能有效地返回数据,这可能是也可能不是聚簇索引的顺序。检查执行计划以查看使用的索引及其扫描方式。
考虑这个例子:
webmethod
在我的SQL 2014系统上,即使扫描了聚簇索引,我也看不到身份值按顺序返回结果。执行计划中的聚簇索引扫描运算符显示USE tempdb;
GO
CREATE DATABASE Demo
ON
(NAME='Demo_Primary1', FILENAME='C:\SqlDataFiles\Demo_Primary', SIZE=10MB)
, (NAME='Demo_Primary2', FILENAME='D:\SqlDataFiles\Demo_Primary2', SIZE=10MB)
LOG ON
(NAME='Demo_Log', FILENAME='D:\SqlLogFiles\Demo_Log.ldf', SIZE=1MB);
GO
USE Demo;
GO
CREATE TABLE [dbo].[Parameter]
(
[ID] [int] IDENTITY(1, 1)
NOT NULL
, [Name] [nvarchar](255) NOT NULL
, CONSTRAINT [PK_Parameter] PRIMARY KEY CLUSTERED ( [ID] ASC )
WITH ( PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON ) ON [PRIMARY]
, CONSTRAINT [UNIQUE_Parameter_Name] UNIQUE NONCLUSTERED ( [Name] ASC )
WITH ( PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON ) ON [PRIMARY]
)
ON [PRIMARY];
GO
WITH
t4 AS (SELECT n FROM (VALUES(0),(0),(0),(0)) t(n))
,t1K AS (SELECT ROW_NUMBER() OVER (ORDER BY (a.n)) AS num
FROM t4 AS a CROSS JOIN t4 AS b CROSS JOIN t4 AS c CROSS JOIN t4 AS d CROSS JOIN t4 AS e)
INSERT INTO dbo.Parameter WITH(TABLOCKX)
SELECT CAST(num AS char(255))
FROM t1K
WHERE num BETWEEN 1 AND 256;
GO
WITH
t4 AS (SELECT n FROM (VALUES(0),(0),(0),(0)) t(n))
,t1K AS (SELECT ROW_NUMBER() OVER (ORDER BY (a.n)) AS num
FROM t4 AS a CROSS JOIN t4 AS b CROSS JOIN t4 AS c CROSS JOIN t4 AS d CROSS JOIN t4 AS e)
INSERT INTO dbo.Parameter WITH(TABLOCKX)
SELECT CAST(num AS char(255))
FROM t1K
WHERE num BETWEEN 257 AND 512;
GO
WITH
t4 AS (SELECT n FROM (VALUES(0),(0),(0),(0)) t(n))
,t1K AS (SELECT ROW_NUMBER() OVER (ORDER BY (a.n)) AS num
FROM t4 AS a CROSS JOIN t4 AS b CROSS JOIN t4 AS c CROSS JOIN t4 AS d CROSS JOIN t4 AS e)
INSERT INTO dbo.Parameter WITH(TABLOCKX)
SELECT CAST(num AS char(255))
FROM t1K
WHERE num BETWEEN 513 AND 768;
GO
WITH
t4 AS (SELECT n FROM (VALUES(0),(0),(0),(0)) t(n))
,t1K AS (SELECT ROW_NUMBER() OVER (ORDER BY (a.n)) AS num
FROM t4 AS a CROSS JOIN t4 AS b CROSS JOIN t4 AS c CROSS JOIN t4 AS d CROSS JOIN t4 AS e)
INSERT INTO dbo.Parameter WITH(TABLOCKX)
SELECT CAST(num AS char(255))
FROM t1K
WHERE num BETWEEN 769 AND 1024;
GO
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
GO
SELECT * FROM dbo.Parameter;
GO
。在这种情况下,SQL Server选择以分配顺序扫描表,而不是遵循页面链接的逻辑顺序,因为Ordered False
隔离级别不需要读取完整性。
即使在其他隔离级别,SQL Server也可能选择扫描不同的索引,这也会导致订单与身份值不同。
答案 1 :(得分:1)
如果没有ORDER BY
语句,记录将按照依赖于生成的查询计划的顺序返回。
在第一种情况下,您将返回三列,并且您的唯一索引不包含所有列。因此,不会使用此命令,查询将扫描主键。
在第二种情况下,您返回两列,唯一索引包含两列(请注意,聚簇索引键始终包含在索引中 - 请参阅https://msdn.microsoft.com/en-us/library/ms177484.aspx),因此这是一个更小且因此更快的索引使用比主键,这意味着读取整行以获取您的数据。
总之,第二个查询可以使用唯一索引作为覆盖索引,第一个不能。