外键列作为覆盖索引

时间:2015-04-29 01:49:15

标签: sql-server

我签约的公司有一组传统的表,它们使用软删除和一些有趣的表结构。联接是PK - > FK关系,但问题是访问不同列的许多不同查询。

写入速率低,读取速率高。因此,它会让我相信在查询使用的多个子列上创建多个覆盖索引不会对性能造成风险,因为只有一个索引。抛开磁盘空间,对于子表FacilityVisit索引(索引),最佳建议是什么。

这是一个非常简化的示例(一些表有不同查询查询的25个列):

CREATE TABLE Person (
 PersonID INT IDENTITY (1,1) 
,FirstName VARCHAR(100)
,Lastname VARCHAR(100)
CONSTRAINT [PK_Person_PersonID] PRIMARY KEY CLUSTERED (PersonID)
)
GO

CREATE TABLE FacilityVisit (
 FacilityVisitID INT IDENTITY (1,1)
,PersonID INT
,VisitDateTime DATETIME
,SecionVisited INT
,ScoreGiven INT
,[Status] BIT
CONSTRAINT [PK_FacilityVisit_FacilityVisitID] PRIMARY KEY CLUSTERED (FacilityVisitID)
)
ALTER TABLE [dbo].[FacilityVisit]  WITH CHECK 
   ADD CONSTRAINT [FK_FacilityVisit_PersonID] FOREIGN KEY([PersonID])
REFERENCES [dbo].[Person] ([PersonID])
GO

/* Possible logical Indexes for FacilityVisit */

CREATE NONCLUSTERED INDEX FK_FacilityVisit_CIndex1 
     ON FacilityVisit ([PersonID])
--OR
CREATE NONCLUSTERED INDEX FK_FacilityVisit_CIndex2 
     ON FacilityVisit ([PersonID],[VisitDateTime],[Status])

--OR 
CREATE NONCLUSTERED INDEX FK_FacilityVisit_CIndex3 
     ON FacilityVisit ([PersonID],[VisitDateTime],[Status]) 
     INCLUDE (SectionVisited,ScoreGiven)

可能的查询:

/* This would best utilzie FK_FacilityVisit_CIndex1 */
SELECT 
 p.FirstName
,P.LastName
FROM Person p
JOIN FacilityVisit fv on fv.PersonID = p.PersonID

/* this would better utilzie FK_FacilityVisit_CIndex2 */
SELECT 
 p.FirstName
,P.LastName
FROM Person p
JOIN FacilityVisit fv on fv.PersonID = p.PersonID
WHERE fv.Status = 1
AND fv.VisitDateTime >= '01/01/2015' AND fv.VisitDateTime <= '12/31/2015'

/* this would best utilzie FK_FacilityVisit_CIndex3 */
SELECT 
 p.Firstname
,p.LastName
,fv.VisitDate
,fv.SectionVisited
,fv.ScoreGiven
FROM Person p
JOIN FacilityVisit fv on fv.PersonID = p.PersonID
WHERE fv.Status = 1
AND fv.VisitDateTime >= '01/01/2015' AND fv.VisitDateTime <= '12/31/2015'

1 个答案:

答案 0 :(得分:0)

首先要记住这一点,测量两次优化一次......每当你想要优化某些东西时,你必须在进行优化之前和之后测量它,如果它没有给出足够的优化,或者它它慢了!撤消优化。

其次,即使你不擅长阅读查询执行计划,看看它们正在运行的查询,通常SQL服务器会推荐它认为有帮助的索引,但是再次测量更改只是为了确保。它们也是了解您应该尝试优化的绝佳方式。

现在您的三个索引示例中,我选择最后一个稍作修改:

CREATE NONCLUSTERED INDEX FK_FacilityVisit_CIndex3 
 ON FacilityVisit ([PersonID],[Status],[VisitDateTime]) 
 INCLUDE (SectionVisited,ScoreGiven)

所有三个可能的查询都可以使用此索引。通过更改关键字段的顺序,您可以将搜索范围缩小到关键字中的单个范围,这意味着可以使用索引搜索来搜索它。但是,如果您没有过滤PersonID,则不太可能使用此索引。

最后,你想要一个覆盖索引,你有2个带有内连接的表,并且你正在指定列:你可以创建一个视图并为它添加一个覆盖索引:

CREATE PersonFacilityVisit
WITH SCHEMABINDING
AS 
SELECT 
     p.PersonID
    ,p.Firstname
    ,p.LastName
    ,fv.FacilityVisitID
    ,fv.VisitDateTime
    ,fv.SecionVisited
    ,fv.ScoreGiven
FROM dbo.Person p
JOIN dbo.FacilityVisit fv on fv.PersonID = p.PersonID
WHERE Status = 1
GO

CREATE UNIQUE CLUSTERED INDEX PK_PersonVisit_View
    ON PersonFacilityVisit (PersonID, FacilityVisitID)

CREATE INDEX IX_PersonVisit_View 
     ON PersonFacilityVisit ([VisitDateTime],[PersonID]) 
     INCLUDE (Firstname,LastName,SecionVisited,ScoreGiven)

您可以阅读有关创建索引视图here的更多信息。