我有两张相似的表格,
CREATE TABLE [dbo].[StockPrices] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[CompanyId] INT NOT NULL,
[Date] DATETIME NOT NULL,
[Open] DECIMAL (18, 2) NOT NULL,
[Close] DECIMAL (18, 2) NOT NULL,
[Low] DECIMAL (18, 2) NOT NULL,
[High] DECIMAL (18, 2) NOT NULL,
[Volume] INT NOT NULL,
CONSTRAINT [PK_dbo.StockPrices] PRIMARY KEY NONCLUSTERED ([Id] ASC),
CONSTRAINT [FK_dbo.StockPrices_dbo.Companies_CompanyId] FOREIGN KEY ([CompanyId]) REFERENCES [dbo].[Companies] ([Id]) ON DELETE CASCADE
);
GO
CREATE CLUSTERED INDEX [IX_CompanyId] ON [dbo].[StockPrices]([CompanyId] ASC);
GO
CREATE NONCLUSTERED INDEX [IX_Date] ON [dbo].[StockPrices]([Date] ASC);
和
CREATE TABLE [dbo].[News] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[NewsProviderId] INT NOT NULL,
[CompanyId] INT NOT NULL,
[Date] DATETIME NOT NULL,
[Title] NVARCHAR (128) NOT NULL,
[Description] NVARCHAR (256) NOT NULL,
[Url] NVARCHAR (256) NOT NULL,
CONSTRAINT [PK_dbo.News] PRIMARY KEY NONCLUSTERED ([Id] ASC),
CONSTRAINT [FK_dbo.News_dbo.Companies_CompanyId] FOREIGN KEY ([CompanyId]) REFERENCES [dbo].[Companies] ([Id]) ON DELETE CASCADE
);
GO
CREATE CLUSTERED INDEX [IX_CompanyId] ON [dbo].[News]([CompanyId] ASC);
GO
CREATE NONCLUSTERED INDEX [IX_Date] ON [dbo].[News]([Date] ASC);
GO
和两个类似的查询
select *
from news
where companyid = 1
and date >= '01/01/2010'
and date <= '01/31/2010'
order by date;
select *
from stockprices
where companyid = 1
and date >= '01/01/2010'
and date <= '01/31/2010'
order by date;
我得到两个完全不同的实际执行计划
查询1:相对于批次:86%
SELECT(COST 0%)&lt; - 嵌套循环(Inneer Join)(成本0%)&lt; - Index Seek(NonClustered)[新闻]。[IX_Date](成本1%) &lt; - Key Lookup(Clustered)[新闻]。[IX_CompanyId](费用99%)
查询2:相对于批次:14%
SELECT(Cost0%)&lt; - Sort(成本33%)&lt; - Clustered Index Scan(Clustered)[StockPrices] IX_CompanyId
我不确定为什么?你能建议吗?
答案 0 :(得分:3)
第一个是在日期顺序中使用非覆盖聚簇索引的搜索和键查找以获取与companyid = 1
匹配的行的剩余列。
第二个是对覆盖索引进行扫描,然后对筛选结果进行排序。
这是一个基于成本的决策,取决于估计匹配的表的比例和两个索引的宽度(some example calculations here)。
密钥查找很昂贵,因为每个密钥查找都需要执行聚簇索引查找以查找相关的页面和行。这意味着必须为非聚集索引查找找到的每个行读取多个页面(与聚簇索引的深度一样多的页面)。此外,为一行找到的聚集索引页很可能不会与下一行的页面相关联,从而导致大量随机IO。
因此,计划切换到索引扫描之前的临界点可能是表的非常低的比例。非覆盖指数在这种情况下可以避免排序的事实可能会使临界点略高于其他情况。
查看每个的估计行数。还要考虑News
表包含各种字符串列,并且可能比聚合索引页上的行少于StockPrices
表中的数值 - 因此News
上的完整聚簇索引扫描可能相对更昂贵,并导致更高的临界点。