Pau*_*aul 1 index sql-server insert
最近我正在阅读这篇博文:http : //blogs.msdn.com/b/sqlazure/archive/2010/05/05/10007304.aspx
其中包含此部分:
选择聚集索引
有几种选择聚集索引的策略;最简单和最好的方法之一是添加另一列数据类型为 datetime 的列,并将该列用于聚集索引。以下是您需要做的:
将列添加为数据类型日期时间
我通常称之为日期
将默认值设置为 GetDate()。
使其非空。
在向您插入数据之前,先在其上创建聚集索引。
我的问题是这是否会为日期创建两个相同的值?如果使用并行性,这个答案会改变吗?(假设从未指定值,总是来自 GetDate())
我相信我的假设是正确的,因为添加了幕后唯一标识符,这无关紧要,对吧?但反正我很感兴趣。
我是从 SQL2008R2 的角度提出问题,但如果答案对 7.0 以上的任何 SQL Server 版本有所不同,我会很感兴趣。
GETDATE()
不能保证是唯一的,不。特别是如果它是一个日期时间,毫秒向上或向下舍入,当然,当并非所有数据都来自同一用户时,你几乎肯定会发生冲突。
当然,聚集索引不需要是唯一的,因为如果不是(但仅在需要时),SQL Server 会使其唯一。如果您需要自己标识特定行(而不是仅用于 SQL Server 内部使用的唯一标识符),并且没有其他候选键列(这可以通过事件日志记录表之类的东西实现),您可以添加一个非聚集的主键,即 IDENTITY 列。或者,如果您真的想要网络规模 - 并且更关心插入性能而不是存储或数据的任何后续使用 - 您可以使用填充有 NEWID() 的 uniqueidentifier 列。
例子
让我们看一个例子,看看它们之间的区别。
USE tempdb;
GO
-- rely on uniqifier
CREATE TABLE dbo.Test1
(
g DATETIME
);
CREATE CLUSTERED INDEX x ON dbo.Test1(g);
-- use an IDENTITY column
CREATE TABLE dbo.Test2
(
i INT IDENTITY(1,1) PRIMARY KEY NONCLUSTERED,
g DATETIME
);
CREATE CLUSTERED INDEX x ON dbo.Test2(g);
-- use a GUID
CREATE TABLE dbo.Test3
(
n UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID()
PRIMARY KEY NONCLUSTERED,
g DATETIME
);
CREATE CLUSTERED INDEX x ON dbo.Test3(g);
GO
Run Code Online (Sandbox Code Playgroud)
插入速度
我使用以下脚本用大约 500,000 行填充了所有三个表:
SET NOCOUNT ON;
GO
SELECT SYSDATETIME();
GO
INSERT dbo.Test1(g)
SELECT DATEADD(SECOND, ABS([object_id])/1000, GETDATE())
FROM sys.all_columns;
GO 100
SELECT SYSDATETIME();
GO
INSERT dbo.Test2(g)
SELECT DATEADD(SECOND, ABS([object_id])/1000,
GETDATE()) FROM sys.all_columns;
GO 100
SELECT SYSDATETIME();
GO
INSERT dbo.Test3(g)
SELECT DATEADD(SECOND, ABS([object_id])/1000,
GETDATE()) FROM sys.all_columns;
GO 100
SELECT SYSDATETIME();
Run Code Online (Sandbox Code Playgroud)
结果:
USE tempdb;
GO
-- rely on uniqifier
CREATE TABLE dbo.Test1
(
g DATETIME
);
CREATE CLUSTERED INDEX x ON dbo.Test1(g);
-- use an IDENTITY column
CREATE TABLE dbo.Test2
(
i INT IDENTITY(1,1) PRIMARY KEY NONCLUSTERED,
g DATETIME
);
CREATE CLUSTERED INDEX x ON dbo.Test2(g);
-- use a GUID
CREATE TABLE dbo.Test3
(
n UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID()
PRIMARY KEY NONCLUSTERED,
g DATETIME
);
CREATE CLUSTERED INDEX x ON dbo.Test3(g);
GO
Run Code Online (Sandbox Code Playgroud)
扫描速度
SELECT SYSDATETIME();
DBCC DROPCLEANBUFFERS;
SELECT * FROM dbo.Test1;
SELECT SYSDATETIME();
DBCC DROPCLEANBUFFERS;
SELECT * FROM dbo.Test2;
SELECT SYSDATETIME();
DBCC DROPCLEANBUFFERS;
SELECT * FROM dbo.Test3;
SELECT SYSDATETIME();
Run Code Online (Sandbox Code Playgroud)
结果:
SET NOCOUNT ON;
GO
SELECT SYSDATETIME();
GO
INSERT dbo.Test1(g)
SELECT DATEADD(SECOND, ABS([object_id])/1000, GETDATE())
FROM sys.all_columns;
GO 100
SELECT SYSDATETIME();
GO
INSERT dbo.Test2(g)
SELECT DATEADD(SECOND, ABS([object_id])/1000,
GETDATE()) FROM sys.all_columns;
GO 100
SELECT SYSDATETIME();
GO
INSERT dbo.Test3(g)
SELECT DATEADD(SECOND, ABS([object_id])/1000,
GETDATE()) FROM sys.all_columns;
GO 100
SELECT SYSDATETIME();
Run Code Online (Sandbox Code Playgroud)
已用空间
查看来自sp_spaceused
以下内容的简单结果:
EXEC sp_spaceused N'dbo.Test1';
EXEC sp_spaceused N'dbo.Test2';
EXEC sp_spaceused N'dbo.Test3';
Run Code Online (Sandbox Code Playgroud)
结果:
Uniquifier: 2.26 seconds
IDENTITY: 3.89 seconds
GUID: 5.06 seconds
Run Code Online (Sandbox Code Playgroud)
uniquifier 占用的空间比 IDENTITY 列少(显然两者都比 GUID 占用的空间少),因为它只用于冲突(可能还有其他我不知道的优化,例如压缩)。
我们还可以查看日期时间列(索引 id = 1)和非聚集主键(索引 id = 2)上的聚集索引的索引页:
DBCC TRACEON(3604,-1);
-- Uniquifier
DBCC IND('tempdb', 'dbo.Test1', 1); -- 1,747 index pages
-- no second index for this table
-- IDENTITY
DBCC IND('tempdb', 'dbo.Test2', 1); -- 1,987 index pages
DBCC IND('tempdb', 'dbo.Test2', 2); -- 1,637 index pages
-- GUID
DBCC IND('tempdb', 'dbo.Test3', 1); -- 2,764 index pages
DBCC IND('tempdb', 'dbo.Test3', 2); -- 3,472 index pages
Run Code Online (Sandbox Code Playgroud)
页/行内容
最后,我们可以查看特定页面以查看连续存储的内容。我只是从上面的每个聚集索引 DBCC IND 结果中取出第一行(您的页面 ID 值几乎肯定会有所不同):
DBCC PAGE('tempdb',1, 153, 1);
DBCC PAGE('tempdb',1, 199, 1);
DBCC PAGE('tempdb',1, 217, 1);
Run Code Online (Sandbox Code Playgroud)
Uniquifier - 特别注意长度/记录大小:
Slot 0, Offset 0x60, Length 15, DumpStyle BYTE
----------------------------^^
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP
Record Size = 15
--------------^^
Memory Dump @0x000000000F7EA060
0000000000000000: 10000c00 0333ba00 fba20000 020000††††.....3º.û¢.....
Slot 1, Offset 0x6f, Length 23, DumpStyle BYTE
----------------------------^^
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS
Record Size = 23
--------------^^
Memory Dump @0x000000000F7EA06F
0000000000000000: 30000c00 0333ba00 fba20000 02000001 †0....3º.û¢......
0000000000000010: 00170001 000000††††††††††††††††††††††.......
Run Code Online (Sandbox Code Playgroud)
IDENTITY 在聚集索引中似乎有 4 个额外的字节:
Slot 0, Offset 0x60, Length 19, DumpStyle BYTE
----------------------------^^
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP
Record Size = 19
--------------^^
Memory Dump @0x0000000011DAA060
0000000000000000: 10001000 a735ba00 fba20000 03020000 †....§5º.û¢......
0000000000000010: 030000†††††††††††††††††††††††††††††††...
Slot 1, Offset 0x73, Length 27, DumpStyle BYTE
----------------------------^^
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS
Record Size = 27
--------------^^
Memory Dump @0x0000000011DAA073
0000000000000000: 30001000 a735ba00 fba20000 04020000 †0...§5º.û¢......
0000000000000010: 03000001 001b0001 000000†††††††††††††...........
Run Code Online (Sandbox Code Playgroud)
GUID 在聚集索引中有一个额外的 16 个字节:
Slot 0, Offset 0x60, Length 31, DumpStyle BYTE
----------------------------^^
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP
Record Size = 31
--------------^^
Memory Dump @0x0000000011DAA060
0000000000000000: 10001c00 393aba00 fba20000 f3233e73 †....9:º.û¢..ó#>s
0000000000000010: a36e114b b1229a80 a5cb090a 030000††††£n.K±".¥Ë ....
Slot 1, Offset 0x7f, Length 39, DumpStyle BYTE
----------------------------^^
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS
Record Size = 39
--------------^^
Memory Dump @0x0000000011DAA07F
0000000000000000: 30001c00 393aba00 fba20000 c7bb2544 †0...9:º.û¢..Ç»%D
0000000000000010: 4ad3574f a2c2029f e4abc9d7 03000001 †JÓWO¢Â.ä«É×....
0000000000000020: 00270001 000000††††††††††††††††††††††.'.....
Run Code Online (Sandbox Code Playgroud)
结论
在我看来,从各方面来看,您最好让 uniquifier 做自己的事情(假设您不希望能够区分具有完全相同日期/时间值的两行)。唯一一次你会遇到麻烦,如果任何单个值被复制 2,147,483,648 次,此时你将溢出整数的 uniquifier 范围。
归档时间: |
|
查看次数: |
7188 次 |
最近记录: |