在索引范围扫描的情况下,整数列索引是否比字符串列索引更快?

时间:2017-04-07 08:50:11

标签: sql sql-server indexing sql-tuning

我在SQL Server上有一个数据库实施任务,其中有一个包含列A的表yearMonth。我不需要日期操作,例如计算当前两个日期之间的天数或月数。 yearMonth可以定义为DateIntvarchar(6)。从节省数据空间的角度来看,4字节Int显然是最佳选择,因为只需要6位数的int,例如201701varchar(6)占用6个字节,Date占用2x4个字节。 (适用于大多数数据库)

但是从索引的角度来看,尤其是在索引范围扫描的情况下?

  • 如果列yearMonth定义为varchar(6),则使用查询select .. from A where yearMonth IN (...)
  • 时可能会发生索引范围扫描
  • 如果列yearMonth定义为IntDate,则可以使用<=<=等运算符进行索引范围扫描。

在上述情况下,当索引范围扫描发生时,哪种类型的列定义更有效?

3 个答案:

答案 0 :(得分:2)

大多数(如果不是全部)DBMS本质上都将日期存储为整数,而对于DateTime,它是两个整数,一个用于日期,一个用于时间,因此两者之间几乎没有差别。我认为你最大的考虑因素是你打算如何使用该列,如果你想对列进行任何类型的日期操作,然后将其存储为日期(默认为该月的第1天)。例如,如果您想知道在201604201701之间有多少个月使用日期会更容易,如果您希望将您的值格式化为April 2017,则会更容易如果它存储为日期。

另一个考虑因素是验证,如果您有varchar(6)或int,则需要额外的检查约束以确保输入的任何值实际上都是有效日期,任何人都可以轻松输入999999,同时年份是有效的,月份不是,而对于varchar,可以输入的废话的可能性是无穷无尽的。

既然您已经标记了SQL Server,我可以更明确地回答 - DATEINT占用4个字节的存储空间,因此不会节省空间,而且从测试开始,两者都可以完全执行相同(日期执行不大,但不是更好,通常读取次数更少),因此使用int没有任何好处(除非您不希望仅限于有效日期)

我使用以下架构进行了一些快速测试:

CREATE TABLE dbo.TDate (ID INT IDENTITY(1, 1) PRIMARY KEY, DT DATE NOT NULL);
INSERT dbo.TDate (DT)
SELECT TOP 100000 DATEADD(MONTH, RAND(CHECKSUM(NEWID())) * 300, '20000101')
FROM sys.all_objects a, sys.all_objects b;

CREATE NONCLUSTERED INDEX IX_TDate_DT ON dbo.TDate (DT);

CREATE TABLE dbo.TInt(ID INT IDENTITY(1, 1) PRIMARY KEY, DT INT NOT NULL);
INSERT dbo.TInt (DT)
SELECT (DATEPART(YEAR, DT) * 100) + DATEPART(MONTH, DT)
FROM dbo.TDate;

CREATE NONCLUSTERED INDEX IX_TInt_DT ON dbo.TInt (DT);

然后运行它以比较性能

DECLARE @D1 DATE = (SELECT TOP 1 DT FROM dbo.TDate ORDER BY NEWID());
DECLARE @D2 DATE = (SELECT TOP 1 DT FROM dbo.TDate WHERE DT > @D1 ORDER BY NEWID());
DECLARE @I1 INT = (DATEPART(YEAR, @D1) * 100) + DATEPART(MONTH, @D1),
        @I2 INT = (DATEPART(YEAR, @D2) * 100) + DATEPART(MONTH, @D2);


SET STATISTICS IO ON;
SET STATISTICS TIME ON;

SELECT  COUNT(*)
FROM    dbo.TDate
WHERE   DT >= @D1
AND     DT < @D2;

SELECT  COUNT(*)
FROM    dbo.TInt
WHERE   DT >= @I1
AND     DT < @I2;

SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;

答案 1 :(得分:0)

Int应该比Varchar(6)更快,因为它占用的空间更少。

SQL SELECT speed int vs varchar

答案 2 :(得分:0)

  

但是从索引的角度来看,尤其是在索引范围扫描的情况下?

范围扫描牢度不受索引类型的限制,但其有效性受到碎片的限制。您的范围扫描查询会更快,如果碎片越少,碎片越少意味着所有页面都相邻且不分散