SQL Server相当于Oracle USING INDEX子句


9

在Oracle中是否有与USING INDEX子句等效的SQL Server 2008?专门针对构造:

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;

有关唯一索引的Sql Server 文档中,它指出了(强调):

唯一索引通过以下方式实现:

主键或唯一约束

创建PRIMARY KEY约束时,如果表上的聚簇索引尚不存在并且未指定唯一的非聚簇索引,则会在一个或多个列上自动创建一个唯一的聚簇索引。主键列不能使用NULL值。

这似乎暗示着有一种方法可以指定应将哪个索引用于主键。


只需与表一起定义PK。create table c (c1 int not null primary key, c2 int)
a_horse_with_no_name 2015年

我感兴趣的是“使PK使用命名索引”部分
。– nik

没有办法做到这一点。主键是约束和索引。在您提供的内容中,默认情况下,主键将是唯一的聚集索引。除非您在where子句中同时包含c1和c2,否则这将使另一个已定义索引重复。
亚伦

Answers:


7

在Oracle中是否有与USING INDEX子句等效的SQL Server 2008?

否。在SQL Server中创建主键或唯一约束时,将使用相同的键自动创建支持该约束的唯一索引。

这似乎暗示着有一种方法可以指定应将哪个索引用于主键。

否。如果您未指定的话,本文档仅试图说明自动支持索引是创建为集群索引还是非集群索引。我同意,这句话措辞混乱。

要澄清的是,当您在不表达首选项的情况下向现有表添加主键约束时,如果表上没有预先存在的聚集索引,则支持索引将被聚集。如果已经有聚集索引,则支持索引将被创建为非聚集索引

您可以使用PRIMARY KEY CLUSTERED或专门请求集群主键或非集群主键PRIMARY KEY NONCLUSTERED

公平地说,有关以下主题的文档更加清晰:

table_constraint(Transact-SQL)


5

用于创建也是主键的聚集索引的SQL Server语法为:

CREATE TABLE dbo.c
(
    c1 INT NOT NULL, 
    c2 INT NOT NULL,
    CONSTRAINT PK_c
    PRIMARY KEY CLUSTERED (c1, c2)
);

据您的评论:“使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);

在SQL Server中,聚集索引表,它们是相同的。聚集索引定义表中存储的行的逻辑顺序。在我的第一个示例中,行以c1c2列的值顺序存储。由于群集密钥也被定义为主键,因此c1和的组合在c2表范围内必须是唯一的。

在第二个示例中,主键由c1c2列组成,但是聚类键只是该c2列。由于我未UNIQUECREATE 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;

我的 tempdb 的结果是:

在此处输入图片说明

在上图中,fn_PhysLocCracker函数的前三列是输出,显示了磁盘上行的物理顺序。您可以看到该slot_id值随c2值(即聚类键)增加了锁定步长。主键索引以不同的顺序存储行,这可以通过强制SQL Server从扫描主键返回结果来看到:

SELECT pkt.c1
    , pkt.c2
FROM dbo.PKTest pkt WITH (INDEX = PK_PKTest, FORCESCAN);

注意,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;

由于我们是专门从索引本身读取的,即查询中没有引用索引外部的列,因此这些%%PHYSLOC%%值表示索引本身中的页面。

结果:

在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.