2016-06-12 306 views
1

我有两个类似的表,SQL执行计划

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(成本为0%)< - 嵌套循环(Inneer加入)(成本为0%)< - 索引查找(非集群)[新闻] [IX_Date。 (成本1%) < - 键查找(群集)[新闻] [IX_CompanyId](成本99%)

查询2:相对于批次:14%

SELECT(Cost0%)< - 排序(成本33%)< - 聚集索引扫描(集群)StockPrices] IX_CompanyId

我不知道为什么?你能建议一些事情吗?

回答

3

第一种方法是在日期顺序和密钥查找的非覆盖聚簇索引上使用seek,以获得匹配companyid = 1的行的其余列。

第二个是对覆盖索引进行扫描,然后对筛选结果进行排序。

这是一个基于成本的决定,具体取决于表中估计匹配的比例和两个索引的宽度(some example calculations here)。

密钥查找很昂贵,因为每个查询都需要执行聚簇索引查找以查找有关的页面和行。这意味着必须为非聚簇索引搜索找到的每个读取多个页面(与聚簇索引的深度一样多的页面)。此外,为一行找到的聚集索引页面很可能不会与下一行的页面相关联,这需要大量的随机IO。

因此,计划切换到索引扫描之前的临界点可能是表格中非常低的比例。在这种情况下,非覆盖指数可以避免排序的事实可能会使转折点高于其他情况。

查看每个行的估计行数。还要考虑News表包含各种字符串列,并且聚集索引页面上的行数可能少于StockPrices表中的数字值 - 因此News上的完整聚簇索引扫描可能相对更昂贵并导致更高的临界点。