综合指数还是单一指数?
Composite index or single index?
在 table 中,我有一个 Date
列,我想按月和年分组。
我创建了两列:DateMonth
和 DateYear
,并用相应的月份和年份填充它们:
UPDATE t SET DateMonth = DATEPART(month, Date), DateYear = DATEPART(year, Date)
这样 groupby 查询将不会使用 DATEPART()
(sql 函数无法利用索引)。
groupby 查询如下:
SELECT DateMonth, DateYear, COUNT(*) AS RowsCount FROM t GROUP BY DateMonth, DateYear
根据该信息,哪种类型的索引会为之前的 groupby 查询提供更好的性能?
索引的每列:
CREATE INDEX IX_DateMonth ON t(DateMonth)
CREATE INDEX IX_DateYear ON t(DateYear)
或覆盖两列的一个索引:
CREATE INDEX IX_DateMonth_DateYear ON t(DateMonth, DateYear)
好吧,他们说找出答案的最好方法就是实际去做 :)
创建了一个包含 100,000 行的 table。
CREATE TABLE DateTable (DateColumn DATETIME , DateMonth INT , DateYear INT)
GO
declare @FromDate date = '1970-01-01'
declare @ToDate date = '2015-12-31'
INSERT INTO DateTable(DateColumn)
select TOP 100000 dateadd(day, rand(checksum(newid())) *
(1+datediff(day, @FromDate, @ToDate)),@FromDate)
FROM master..spt_values v cross join master..spt_values v2
GO
UPDATE DateTable
set DateMonth = MONTH(DateColumn)
,DateYear = YEAR(DateColumn)
GO
查询
在两列上使用单个索引并在两列上使用两个单独的索引执行以下查询。
SELECT DateMonth, DateYear, COUNT(*) AS RowsCount
从日期表
按日期月份、日期年份分组
两个独立的索引
CREATE INDEX IX_DateMonth ON DateTable(DateMonth)
GO
CREATE INDEX IX_DateYear ON DateTable(DateYear)
GO
具有两个独立索引的执行计划
综合指数
CREATE INDEX IX_DateMonth_DateYear7
ON DateTable(DateMonth, DateYear)
GO
两个索引不同的表
最后我创建了两个 tables,DateTable 在两列上有两个单独的索引,DateTable2 在两列上有一个复合索引,并比较了执行计划:
故事寓意
坚持使用一个复合索引,因为您按两个列进行分组,复合索引将导致非聚集索引扫描,这将比 table 扫描便宜,如果您有两个单独的索引两列上的索引。
在 table 中,我有一个 Date
列,我想按月和年分组。
我创建了两列:DateMonth
和 DateYear
,并用相应的月份和年份填充它们:
UPDATE t SET DateMonth = DATEPART(month, Date), DateYear = DATEPART(year, Date)
这样 groupby 查询将不会使用 DATEPART()
(sql 函数无法利用索引)。
groupby 查询如下:
SELECT DateMonth, DateYear, COUNT(*) AS RowsCount FROM t GROUP BY DateMonth, DateYear
根据该信息,哪种类型的索引会为之前的 groupby 查询提供更好的性能?
索引的每列:
CREATE INDEX IX_DateMonth ON t(DateMonth)
CREATE INDEX IX_DateYear ON t(DateYear)
或覆盖两列的一个索引:
CREATE INDEX IX_DateMonth_DateYear ON t(DateMonth, DateYear)
好吧,他们说找出答案的最好方法就是实际去做 :)
创建了一个包含 100,000 行的 table。
CREATE TABLE DateTable (DateColumn DATETIME , DateMonth INT , DateYear INT)
GO
declare @FromDate date = '1970-01-01'
declare @ToDate date = '2015-12-31'
INSERT INTO DateTable(DateColumn)
select TOP 100000 dateadd(day, rand(checksum(newid())) *
(1+datediff(day, @FromDate, @ToDate)),@FromDate)
FROM master..spt_values v cross join master..spt_values v2
GO
UPDATE DateTable
set DateMonth = MONTH(DateColumn)
,DateYear = YEAR(DateColumn)
GO
查询
在两列上使用单个索引并在两列上使用两个单独的索引执行以下查询。
SELECT DateMonth, DateYear, COUNT(*) AS RowsCount 从日期表 按日期月份、日期年份分组
两个独立的索引
CREATE INDEX IX_DateMonth ON DateTable(DateMonth)
GO
CREATE INDEX IX_DateYear ON DateTable(DateYear)
GO
具有两个独立索引的执行计划
综合指数
CREATE INDEX IX_DateMonth_DateYear7
ON DateTable(DateMonth, DateYear)
GO
两个索引不同的表
最后我创建了两个 tables,DateTable 在两列上有两个单独的索引,DateTable2 在两列上有一个复合索引,并比较了执行计划:
故事寓意
坚持使用一个复合索引,因为您按两个列进行分组,复合索引将导致非聚集索引扫描,这将比 table 扫描便宜,如果您有两个单独的索引两列上的索引。