一张表中的行是随机排序的

时间:2016-03-03 12:38:27

标签: sql sql-server

我目前正在开发一个在Microsoft SQL Server上保存数据的应用程序。在测试时我注意到在一个表中,行看似随机排序,而在所有其他表中,它们按主键排序,这是一个自动递增的整数。

示例:

有序表:

Ordered Table

随机顺序:

enter image description here

我知道我可以在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]

2 个答案:

答案 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),因此这是一个更小且因此更快的索引使用比主键,这意味着读取整行以获取您的数据。

总之,第二个查询可以使用唯一索引作为覆盖索引,第一个不能。