select MAX(date), TypeId, DirectionId
from mqview.[Message]
where RecActive = 1
group by TypeId, DirectionId
DirectionId仅包含值1(I - 输入)和2(O - 输出)。 TypeId现在包含10种类型。 DirectionId和typeId是其代码列表的外键。表消息目前包含> 3.6百万条记录。我添加了正确的索引,执行上查询~1.5秒,但我希望它更快。索引定义:
create index covering_index ON [mqview].[Message] (TypeId, DirectionId, [Date] desc)
对每个TypeId执行速度很快(仅遍历索引树)。
select top 1 * from mqview.Message where RecActive = 1 and TypeId = 2 and DirectionId = 1 order by id desc
但类型代码列表包含10种类型,因此这会产生20个查询(Direction使它成为2次)。我认为group by的延迟时间最长。有没有办法在没有分组的情况下重写它?
我正在使用Microsoft SQL Server 2014。
更新
查询我用来获得结果实际上现在是这样的:
select m.Date as 'Date', t.Code as 'Type', d.Code as 'Direction'
from
mqview.Message m
inner join mqview.MessageType t on (t.id = m.TypeId)
inner join mqview.MessageDirection d on (d.Id = m.DirectionId)
where
t.Visible = 1
and m.Id in (
SELECT
MAX(Id)
FROM
mqview.[Message]
where
RecActive = 1 and Date is not null
GROUP BY
TypeId,
DirectionId
)
在添加由Gordon Linoff(稍微不同)提取的索引之后,查询现在执行~1s。
create index covering_index ON [mqview].[Message] (RecActive, Date desc, TypeId, DirectionId,) include (id);
我不确定是否需要include(id)
。没有include(id)
索引指向RowID(指向表行),include(id)
索引存储Id(因此覆盖索引),但运行查询没有include
(删除索引,创建新一个)没有时间差异。
答案 0 :(得分:2)
如果我不得不推测,问题是where
条款。尝试创建包含该子句的索引:
create index covering_index ON [mqview].[Message] (RecActive, TypeId, DirectionId, [Date] desc) ;
或者,因此更好地使用现有索引,切换到条件聚合:
select max(case when RecActive = 1 then date end), TypeId, DirectionId
from mqview.[Message]
group by TypeId, DirectionId;
当您对每种类型独立进行查询时,类型和方向以及where
子句中的条件,所有子句具有由and
s连接的相等比较。因此,优化器可以使用现有索引,在数据页中查找RecActive
。
您的问题的答案是,还有其他方法可以编写查询,但如果没有正确的索引,它们可能会遇到相同的问题。一个想法是使用相关子查询:
select m.*
from mqview.[Message] m
where m.RecActive = 1 and
m.date = (select max(m2.date)
from mqview.[Message] m2
where m2.RecActive = 1 and m2.typeid = m.typeid and m2.directionid = m.directionid
);
如果您有类型和方向的列表:
select t.typeid, d.directionid, m.date
from types t cross join
dimensions d cross apply
(select top 1 m.date
from mqview.[Message] m
where m.typeid = t.typeid and m.directionid = d.directionid and
RecActive = 1
order by date desc
) m;
答案 1 :(得分:0)
我认为使用适当的索引分区会更快。试试这个
; WITH CTE AS
(
SELECT IIF(RecActive = 1, date, ''), TypeID, DirectionId, ROW_NUMBER() OVER (PARTITION BY TypeID, DirectionID ORDER BY date DESC)
FROM mqview.[Message]
)
SELECT * FROM CTE CTE
WHERE CTE.RN = 1
答案 2 :(得分:0)
试试这个:
select max.date, T.* from
(select distinct TypeId, DirectionId from mqview.[Message] where RecActive = 1) T
outer apply (select top 1 date from mqview.[Message] where RecActive = 1 and T.TypeID = TypeID and T.DirectionId = DirectionID order by date desc ) max