2014-04-10 36 views
1

我们正在使用SQLServer 2008,并对许多表具有“只插入”模式。适用于“仅插入”模式的SQL服务器索引

的排序表中,我们已经是一个例子(这只是一个例子):

create table spotquotes 
(
    Id numeric(19,0) identity(1,1) not null primary key clustered, 
    feeditem_id numeric(19,0) not null, 
    value_ask float not null, 
    value_bid float not null, 
    effectiveDateUTC datetime not null default getutcdate() 
) 

我们则与此查询

select * from spotquotes q 
inner join 
    (select feeditem_id, max(id) as latest from spotquotes group by feeditem_id) q2 
    on q.id = q2.latest and q.feeditem_id = q2.feeditem_id 

其实查询表,它有必要创建上述查询的观点:

create view latestspotquotes as 
select * from spotquotes q 
inner join 
    (select feeditem_id, max(id) as latest from spotquotes group by feeditem_id) q2 
    on q.id = q2.latest and q.feeditem_id = q2.feeditem_id 

即我们想要的“最新”插入到表中的每个费ditem_id - 但我们也有能力查询过去任何时候的表的状态(这对于审计考虑非常好)。

一个更简单的方法来说明。我希望优化以下查询:

select feeditem_id, max(id) as latest from spotquotes group by feeditem_id 

此表通常有数亿行的 - 但少数feeditem_id情况下,这很可能是在表的末尾的。

使用此表中的现有主键和约1亿行,SQL Server 2008需要6秒钟才能执行此查询 - 速度非常慢。

所以我想知道 - 如果我们要为这个表创建一个索引来加速这个查询,我们应该创建什么索引?

不幸的是,管理工作室并没有为我们建议索引。

编辑:仍有问题,但我会提出作为一个单独的问题。

UPDATE

更快的查询(< 10毫秒)可以通过使用“交叉应用”连同选择顶部* ... ORDER BY编号降序被哄骗了SQL服务器。详细信息请参见Convincing SQL server to search backwards on clustered index for an insert only schema

+0

'(选择feeditem_id,MAX(ID)的最新作ID)' - 你确定这是正确的? – dean

+0

您的嵌套查询位于同一个表或不同的表上? – raholling

+0

raholling - 这是同一张桌子。 –

回答

0

对于此查询:

select feeditem_id, max(id) as latest from spotquotes group by feeditem_id 

创建以下非聚集索引

CREATE INDEX IX_Spotquotes_feeditem_id on spotquotes(feeditem, id) 
+0

非常感谢主任 - 我现在就试试这个。小错字应该是spotquotes(feeditem_id,id) –

+0

不幸的是,虽然showplan_xml显示它现在使用这个索引,它*仍然*需要5秒! –

+0

如果它是有序的索引扫描,就是这样。你是否选择了这两个以外的其他列? – dean

1

仅插入索引:S我只是插入精简插入模式最好不带任何索引,但在表上有任何索引将会影响插入操作的性能。

什么样

CREATE NONCLUSTERED INDEX NIX_feeditem_id_effectiveDateUTC 
ON dbo.spotquotes(feeditem_id ASC, effectiveDateUTC DESC) 
GO 

,现在在创建和feeditem_id领域effectiveDateUTC的东西写索引查询类似.....

;WITH LastestRecords 
AS(
    SELECT Id 
     ,feeditem_id 
     ,value_ask 
     ,value_bid 
     ,effectiveDateUTC 
     ,ROW_NUMBER() OVER (PARTITION BY feeditem_id ORDER BY ffectiveDateUTC DESC) AS RN 
    FROM spotquotes 
) 
SELECT Id 
     ,feeditem_id 
     ,value_ask 
     ,value_bid 
     ,effectiveDateUTC 
FROM LastestRecords 
WHERE RN = 1 

OR

创建索引如下

CREATE NONCLUSTERED INDEX NIX_feeditem_id_Id 
ON dbo.spotquotes(feeditem_id ASC, ID DESC) 
GO 

查询

;WITH LastestRecords 
AS(
    SELECT Id 
     ,feeditem_id 
     ,value_ask 
     ,value_bid 
     ,effectiveDateUTC 
     ,ROW_NUMBER() OVER (PARTITION BY feeditem_id ORDER BY Id DESC) AS RN 
    FROM spotquotes 
) 
SELECT Id 
     ,feeditem_id 
     ,value_ask 
     ,value_bid 
     ,effectiveDateUTC 
FROM LastestRecords 
WHERE RN = 1 
+0

'INSERT Only'是指你不执行'UPDATE'操作的事实。相反,您插入一条新记录,保留旧记录并使用业务逻辑来确定要从哪些记录中选择*(它们“当前有效”)*。 – MatBailie

+0

对。只需添加 - 正确索引ROW_NUMBER()意味着在'(partitioning_columns,order_by_columns)'上创建一个复合索引,可能包含更好性能的列,并且如果存在静态WHERE子句,可能会对其进行过滤。 – dean

+0

我不太明白这是如何工作 - 但我想要一个答案,实现正确的查询计划*无需*必须更改SQL查询...应该是可能的不应该吗? –