是否可以在

时间:2016-09-06 10:24:00

标签: sql group-by

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(删除索引,创建新一个)没有时间差异。

3 个答案:

答案 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