下面是我的创建表脚本: -
CREATE TABLE [dbo].[PatientCharts](
[PatientChartId] [uniqueidentifier] ROWGUIDCOL NOT NULL,
[FacilityId] [uniqueidentifier] NOT NULL,
[VisitNumber] [varchar](200) NOT NULL,
[MRNNumber] [varchar](100) NULL,
[TimeIn] [time](7) NULL,
[TimeOut] [time](7) NULL,
[DateOfService] [date] NULL,
[DateOut] [date] NULL),
我在PatientChartId上有一个聚集索引,在VisitNumber和MRNNumber上有两个非聚集索引。该表有数百万条记录。
以下查询正在进行聚簇索引扫描: -
SELECT *
FROM dbo.PatientCharts
INNER JOIN ( SELECT FacilityID
FROM Facilities
WHERE RemoteClientDB IN (
SELECT SiteID
FROM RemoteClient WITH ( NOLOCK )
WHERE Code = 'IN-ESXI-EDISC14'
)
) AS Filter ON dbo.PatientCharts.FacilityId = Filter.FacilityID
由于数据量的原因,这种聚集索引扫描在生产中花费了大量时间。
执行计划是: -
我甚至尝试在FacilityID上添加一个非clusted索引并包括PatientChartID但仍然是相同的执行计划。
我每次都在做DBCC FREEPROCCACHE,以指示sql server每次都使用新的计划。
我还有什么其他方法可以阻止聚类索引扫描吗?
答案 0 :(得分:2)
由于没有索引支持您的查询,因此将发生群集扫描。即使您对FacilityID和PatientChartID进行索引,由于超过临界点(Google Kimberly Tripp Tipping Point),您仍有可能要求扫描足够数量的数据
没有简单的方法可以说下一部分,但是对于一个拥有数百万条记录的系统,但这样一个简单的查询会导致您遇到问题,您将不得不更多地了解索引的一般情况以及如何SQL计划引擎的行为。我会推荐Kalen Delany的SQL Internals,如果你在这里搜索书籍推荐,那么就会有一些很好的建议。
答案 1 :(得分:0)
您是否尝试将此实现为具有内部联接的直接查询,而不是为每个步骤使用子查询?
如果您将查询更改为以下格式,我很乐意看看生成的执行计划:
select * from patientschart...
inner join facilities...
inner join remoteclientdb....
where...
我认为一旦你摆脱了子查询,优化器就会选择正确的索引。试一试并分享执行计划。
另外,另一方面,您是否需要结果集中的所有字段?您可以通过在选择列表中切换到特定列而不是*来获益。
我希望这会有所帮助。
答案 2 :(得分:0)
正如安德鲁所说,你的聚集索引在这里没有帮助你或伤害你 - 如果你没有聚集索引,你会看到一个表扫描(我保证你不会比这更有趣)聚集索引扫描)。
假设这是此表上最重要的查询,我会说您应该更改表设计,以便聚集索引在FacilityID上。那会快得多。
答案 3 :(得分:0)
我认为您应该避免执行SELECT *
并指定所需的列。然后,您可以根据您获得的执行计划计划索引