临时表索引/性能帮助请求

Posted

技术标签:

【中文标题】临时表索引/性能帮助请求【英文标题】:Temp table index/ performance help requested 【发布时间】:2012-08-25 20:26:37 【问题描述】:

这是我之前帖子的延续:RowNumber() and Partition By performance help wanted

我有一个查询需要显着提高性能。根据上一篇文章中的建议,我在查询中消除了除一个 cte 之外的所有内容,并实现了一个带有索引的临时表。它仍然很慢......目前 40 分钟还在计数,还没有返回数据。一些背景信息:所有数据来自的一张表大约有 500 万行。它上面有几个索引,包括一个唯一的非聚集索引,它由 Symbol、Period 和 TradeDate 列组成,其中包括 Value 列。我还有另外两个完全相同,但先是 Period,然后是 TradeDate。表上还有一个唯一的聚集索引。什么可以加快这个速度?临时表上的不同索引?抱歉,有一个半重复的帖子。我在这里停滞不前。任何帮助都会很大。

create table ##smaComp
(
    RowNum          bigint,
    Rank            bigint,
    TradeDate       Date,
    Symbol          Char(6),
    FastPer         int,
    FastVal         Decimal(9,4),
    SlowPer         int,
    SlowVal         Decimal(9,4),
    FastMinusSlow   Decimal(9,4)
)

;with sma as
(
    select t.TradeDate, t.Symbol, t.Period FastPer, t.Value FastVal, t2.Period SlowPer, 
        t2.Value SlowVal, (t.Value-t2.Value) FastMinusSlow
    from tblDailySMA t join tblDailySMA as t2 on t.Symbol = t2.Symbol 
        and t.TradeDate = t2.TradeDate and t2.Period > t.Period
)

insert into ##smaComp
(
    RowNum, Rank, TradeDate, Symbol, FastPer, FastVal, SlowPer, SlowVal, FastMinusSlow
)
select ROW_NUMBER() OVER (PARTITION BY sma.Symbol, sma.FastPer, sma.SlowPer
    ORDER BY sma.TradeDate) as RowNum, DENSE_RANK() OVER (ORDER BY sma.Symbol, sma.FastPer,
    sma.SlowPer) as Rank, sma.TradeDate, sma.Symbol, sma.FastPer, sma.FastVal, 
    sma.SlowPer, sma.SlowVal, sma.FastMinusSlow
from sma

CREATE UNIQUE NONCLUSTERED INDEX [IX_tblDailySMAClustered] ON ##smaComp
(RowNum, Rank)
INCLUDE (Symbol, TradeDate, FastPer, SlowPer, FastVal, SlowVal, FastMinusSlow)

select t.TradeDate as PriorDate, t.FastPer, t.FastVal, t.SlowPer, t.SlowVal,
    t.FastMinusSlow, t2.TradeDate as LatestDate, t2.FastPer, t2.FastVal, t2.SlowPer, 
    t2.SlowVal, t2.FastMinusSlow, (t2.FastMinusSlow * t2.FastMinusSlow) as Comparison
from ##smaComp t join ##smaComp t2
on t.Rank = t2.Rank and t.RowNum = (t2.RowNum - 1)

按要求执行计划:

StmtText
  create table ##smaComps  (   RowNum   bigint,   Rank   bigint,   TradeDate  Date,   Symbol   Char(6),   FastPer   int,   FastVal   Decimal(9,4),   SlowPer   int,   SlowVal   Decimal(9,4),   FastMinusSlow Decimal(9,4)  )
;with sma as  (   select t.TradeDate, t.Symbol, t.Period FastPer, t.Value FastVal, t2.Period SlowPer,     t2.Value SlowVal, (t.Value-t2.Value) FastMinusSlow   from tblDailySMA t join tblDailySMA as t2 on t.Symbol = t2.Symbol     and t.TradeDate = t2.TradeDate and t2.Period > t.Period  )    insert into ##smaComps  (   RowNum, Rank, TradeDate, Symbol, FastPer, FastVal, SlowPer, SlowVal, FastMinusSlow  )  select ROW_NUMBER() OVER (PARTITION BY sma.Symbol, sma.FastPer, sma.SlowPer   ORDER BY sma.TradeDate) as RowNum, DENSE_RANK() OVER (ORDER BY sma.Symbol, sma.FastPer,   sma.SlowPer) as Rank, sma.TradeDate, sma.Symbol, sma.FastPer, sma.FastVal,    sma.SlowPer, sma.SlowVal, sma.FastMinusSlow  from sma

StmtText
  |--Table Insert(OBJECT:([tempdb].[dbo].[##smaComps]), SET:([tempdb].[dbo].[##smaComps].[RowNum] = [Expr1009],[tempdb].[dbo].[##smaComps].[Rank] = [Expr1010],[tempdb].[dbo].[##smaComps].[TradeDate] = [Market].[dbo].[tblDailySMA].[TradeDate] as [t].[TradeDate],[tempdb].[dbo].[##smaComps].[Symbol] = [Expr1011],[tempdb].[dbo].[##smaComps].[FastPer] = [Market].[dbo].[tblDailySMA].[Period] as [t].[Period],[tempdb].[dbo].[##smaComps].[FastVal] = [Expr1012],[tempdb].[dbo].[##smaComps].[SlowPer] = [Market].[dbo].[tblDailySMA].[Period] as [t2].[Period],[tempdb].[dbo].[##smaComps].[SlowVal] = [Expr1013],[tempdb].[dbo].[##smaComps].[FastMinusSlow] = [Expr1014]))
       |--Compute Scalar(DEFINE:([Expr1014]=CONVERT_IMPLICIT(decimal(9,4),[Expr1008],0)))
            |--Top(ROWCOUNT est 0)
                 |--Compute Scalar(DEFINE:([Expr1011]=CONVERT_IMPLICIT(char(6),[Market].[dbo].[tblDailySMA].[Symbol] as [t].[Symbol],0), [Expr1012]=CONVERT_IMPLICIT(decimal(9,4),[Market].[dbo].[tblDailySMA].[Value] as [t].[Value],0), [Expr1013]=CONVERT_IMPLICIT(decimal(9,4),[Market].[dbo].[tblDailySMA].[Value] as [t2].[Value],0)))
                      |--Sequence Project(DEFINE:([Expr1010]=dense_rank))
                           |--Segment
                                |--Segment
                                     |--Sequence Project(DEFINE:([Expr1009]=row_number))
                                          |--Segment
                                               |--Compute Scalar(DEFINE:([Expr1008]=[Market].[dbo].[tblDailySMA].[Value] as [t].[Value]-[Market].[dbo].[tblDailySMA].[Value] as [t2].[Value]))
                                                    |--Parallelism(Gather Streams, ORDER BY:([t].[Symbol] ASC, [t].[Period] ASC, [t2].[Period] ASC, [t].[TradeDate] ASC))
                                                         |--Sort(ORDER BY:([t].[Symbol] ASC, [t].[Period] ASC, [t2].[Period] ASC, [t].[TradeDate] ASC))
                                                              |--Merge Join(Inner Join, MANY-TO-MANY MERGE:([t].[TradeDate], [t].[Symbol])=([t2].[TradeDate], [t2].[Symbol]), RESIDUAL:([Market].[dbo].[tblDailySMA].[Symbol] as [t].[Symbol]=[Market].[dbo].[tblDailySMA].[Symbol] as [t2].[Symbol] AND [Market].[dbo].[tblDailySMA].[TradeDate] as [t].[TradeDate]=[Market].[dbo].[tblDailySMA].[TradeDate] as [t2].[TradeDate] AND [Market].[dbo].[tblDailySMA].[Period] as [t2].[Period]>[Market].[dbo].[tblDailySMA].[Period] as [t].[Period]))
                                                                   |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([t].[TradeDate], [t].[Symbol]), ORDER BY:([t].[TradeDate] ASC, [t].[Symbol] ASC))
                                                                   |    |--Index Scan(OBJECT:([Market].[dbo].[tblDailySMA].[IX_tblDailySMA_TrDateNonClust] AS [t]), ORDERED FORWARD)
                                                                   |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([t2].[TradeDate], [t2].[Symbol]), ORDER BY:([t2].[TradeDate] ASC, [t2].[Symbol] ASC))
                                                                        |--Index Scan(OBJECT:([Market].[dbo].[tblDailySMA].[IX_tblDailySMA_TrDateNonClust] AS [t2]), ORDERED FORWARD)

StmtText
 CREATE UNIQUE NONCLUSTERED INDEX [IX_tblDailySMAClustered] ON ##smaComps  (RowNum, Rank)  INCLUDE (Symbol, TradeDate, FastPer, SlowPer, FastVal, SlowVal, FastMinusSlow)
 select t.TradeDate as PriorDate, t.FastPer, t.FastVal, t.SlowPer, t.SlowVal,   t.FastMinusSlow, t2.TradeDate as LatestDate, t2.FastPer, t2.FastVal, t2.SlowPer,    t2.SlowVal, t2.FastMinusSlow, (t2.FastMinusSlow * t2.FastMinusSlow) as Comparison  from ##smaComps t join ##smaComps t2  on t.Rank = t2.Rank and t.RowNum = (t2.RowNum - 1)

StmtText
  |--Hash Match(Inner Join, HASH:([t].[Rank], [t].[RowNum])=([t2].[Rank], [Expr1007]), RESIDUAL:([tempdb].[dbo].[##smaComps].[Rank] as [t].[Rank]=[tempdb].[dbo].[##smaComps].[Rank] as [t2].[Rank] AND [tempdb].[dbo].[##smaComps].[RowNum] as [t].[RowNum]=[Expr1007]))
       |--Table Scan(OBJECT:([tempdb].[dbo].[##smaComps] AS [t]))
       |--Compute Scalar(DEFINE:([Expr1006]=[tempdb].[dbo].[##smaComps].[FastMinusSlow] as [t2].[FastMinusSlow]*[tempdb].[dbo].[##smaComps].[FastMinusSlow] as [t2].[FastMinusSlow], [Expr1007]=[tempdb].[dbo].[##smaComps].[RowNum] as [t2].[RowNum]-(1)))
            |--Table Scan(OBJECT:([tempdb].[dbo].[##smaComps] AS [t2]))

【问题讨论】:

您能否向我们展示该查询的执行计划? 当然可以。我希望格式可以接受.. 【参考方案1】:

查询计划不包含任何可能出错的内容(例如嵌套循环爆炸)。

我认为原因是您在所有“时期”中交叉加入。我的猜测是您的数据每个 TradeDate 和 Symbol 包含许多(100 个?)周期。这意味着 SQL Server 必须处理二次数据量。谓词 t2.Period > t.Period 过滤了大约一半的行,但剩下的一半。

所以原则上数据量非常高。不确定这是否可以优化。您需要所有数据还是只需要一个子集?如果您需要所有这些,我认为没有什么可以做的。

您可以通过将查询限制为一个 TradeDate 和 Symbol 并查看行数来检验这一假设。

【讨论】:

我想我只是需要一位更高级的开发人员就我的时间相对于所涉及的处理是否是标准时间提出意见。谢谢。

以上是关于临时表索引/性能帮助请求的主要内容,如果未能解决你的问题,请参考以下文章

MySQL5.7性能优化系列——SQL语句优化——使用物化策略优化子查询

数据库查询优化——给临时表建索引

MySQL创建高性能索引考点

MySQL创建高性能索引考点

MySQL创建临时表?

3.2 索引的优点