nik*_*nik 9 sql-server-2008 oracle sql-server constraint primary-key
是否有 SQL Server 2008 等效于 Oracle 中的 USING INDEX 子句?特别是对于构造:
CREATE TABLE c(c1 INT, c2 INT);
CREATE INDEX ci ON c (c1, c2);
ALTER TABLE c ADD CONSTRAINT cpk PRIMARY KEY (c1) USING INDEX ci;
Run Code Online (Sandbox Code Playgroud)
在关于唯一索引的 Sql Server文档中,它指出(强调):
唯一索引通过以下方式实现:
PRIMARY KEY 或 UNIQUE 约束
当您创建 PRIMARY KEY 约束时,如果表上的聚集索引尚不存在并且您没有指定唯一的非聚集索引,则会自动创建一个或多个列上的唯一聚集索引。主键列不能允许 NULL 值。
这似乎意味着有一种方法可以指定主键应该使用什么索引。
是否有 SQL Server 2008 等效于 Oracle 中的 USING INDEX 子句?
否。当您在 SQL Server 中创建主键或唯一约束时,会自动创建一个唯一索引来支持该约束,并使用相同的键。
这似乎意味着有一种方法可以指定主键应该使用什么索引。
否。如果您未指定,该文档只是试图解释自动支持索引是否将创建为集群或非集群。措辞令人困惑,我同意。
澄清一下,当您向现有表添加主键约束而不表示偏好时,如果表上没有预先存在的聚集索引,则支持索引将被聚集。如果已经存在聚集索引,则支持索引将创建为非聚集索引
您可以使用:PRIMARY KEY CLUSTERED
或专门请求集群或非集群主键PRIMARY KEY NONCLUSTERED
。
公平地说,有关该主题的文档更加清晰:
table_constraint (Transact-SQL)
用于创建也是主键的聚集索引的 SQL Server 语法是:
CREATE TABLE dbo.c
(
c1 INT NOT NULL,
c2 INT NOT NULL,
CONSTRAINT PK_c
PRIMARY KEY CLUSTERED (c1, c2)
);
Run Code Online (Sandbox Code Playgroud)
至于您的评论:“使 PK 使用命名索引”,上面的代码将导致主键索引被命名为“PK_c”。
主键和聚集键不必是相同的列。您可以分别定义它们。在上面的示例中,将CLUSTERED
关键字更改为NONCLUSTERED
,然后使用以下CREATE INDEX
语法简单地添加聚集索引:
CREATE TABLE dbo.c
(
c1 INT,
c2 INT,
CONSTRAINT PK_c
PRIMARY KEY NONCLUSTERED (c1, c2)
);
CREATE CLUSTERED INDEX CX_c ON dbo.c (c2);
Run Code Online (Sandbox Code Playgroud)
在 SQL Server 中,聚集索引就是表,它们是一模一样的。聚集索引定义存储在表中的行的逻辑顺序。在我的第一个示例中,行按照c1
和c2
列的值的顺序存储。由于聚集键也被定义作为主键的组合,c1
并且c2
必须是唯一的表范围。
在第二个示例中,主键由c1
和c2
列组成,但集群键只是c2
列。由于我没有UNIQUE
在CREATE INDEX
语句中指定属性,因此集群键 ( c2
) 不需要在整个表中是唯一的。SQL Server 将自动创建“uniquifier”并将其附加到c2
列中的值以创建集群键。这个集群键,因为它现在是唯一的,然后将被用作在表上创建的其他索引中的行 ID。
为了证明集群键控制存储中行的布局,您可以使用未记录的函数fn_PhysLocCracker(%%PHYSLOC%%)
. 以下代码显示了行在磁盘上按c2
列的顺序排列,我将其定义为集群键:
USE tempdb;
CREATE TABLE dbo.PKTest
(
c1 INT NOT NULL
, c2 INT NOT NULL
, c3 VARCHAR(256) NOT NULL
);
ALTER TABLE PKTest
ADD CONSTRAINT PK_PKTest
PRIMARY KEY NONCLUSTERED (c1, c2);
CREATE CLUSTERED INDEX CX_PKTest
ON dbo.PKTest(c2);
TRUNCATE TABLE dbo.PKTest;
INSERT INTO dbo.PKTest (c1, c2, c3)
SELECT TOP(25) o1.object_id / o2.object_id, o2.object_id, o1.name + '.' + o2.name
FROM sys.objects o1
, sys.objects o2
WHERE o1.object_id >0
and o2.object_id > 0;
SELECT plc.file_id
, plc.page_id
, plc.slot_id
, pk.*
FROM dbo.PKTest pk
CROSS APPLY fn_PhysLocCracker(%%PHYSLOC%%) plc;
Run Code Online (Sandbox Code Playgroud)
我的tempdb的结果是:
在上图中,前三列是fn_PhysLocCracker
函数的输出,显示了磁盘上行的物理顺序。可以看到该slot_id
值与该值增加了锁步,该c2
值是聚类键。主键索引以不同的顺序存储行,可以通过强制 SQL Server 返回扫描主键的结果来看到:
SELECT pkt.c1
, pkt.c2
FROM dbo.PKTest pkt WITH (INDEX = PK_PKTest, FORCESCAN);
Run Code Online (Sandbox Code Playgroud)
请注意,我没有ORDER BY
在上述语句中使用子句,因为我试图显示主键索引中项目的顺序。
上述查询的输出是:
查看fn_PhysLocCracker
函数,我们可以看到主键索引的物理顺序。
SELECT plc.file_id
, plc.page_id
, plc.slot_id
, pkt.c1
, pkt.c2
FROM dbo.PKTest pkt WITH (INDEX = PK_PKTest, FORCESCAN)
CROSS APPLY fn_PhysLocCracker(%%PHYSLOC%%) plc;
Run Code Online (Sandbox Code Playgroud)
由于我们只从索引本身读取数据,即查询中没有引用索引之外的列,因此这些%%PHYSLOC%%
值代表索引本身中的页面。
结果:
归档时间: |
|
查看次数: |
1761 次 |
最近记录: |