SELECT需要1秒INSERT @TableVar SELECT需要45秒

时间:2013-09-18 20:46:59

标签: sql sql-server tsql sql-server-2012

我有一个select语句,在2.55亿行的表上执行sub-second。结果大约有50行。

当我尝试执行INSERT @Tbl SELECT ...时,查询需要45秒。

有人可以向我解释一下吗?

这是完整的批次。计时器是127秒。当插入行被注释掉时,Timer为2秒。

DBCC DROPCLEANBUFFERS
GO

DBCC FREEPROCCACHE
GO


declare @fr datetime = '2013-01-01', @to datetime = '2013-09-01'
declare @TempTable table (Title varchar(50), PlayCount int, Wt float)

declare @t1 datetime = getdate()

    insert @TempTable
    select Title, PlayCount, MaxCount * 1.0 / PlayCount as Weight
    from (
        select l.SkinDescription as Title, count(*) as PlayCount, max(count(*)) OVER() AS MaxCount
        from LegalConfiguration l 
        join Play p on p.LegalConfigNumber = l.SequenceNumber
        where p.CurrentDate between @fr and @to
        group by l.SkinDescription
    ) sub

declare @t2 datetime = getdate()

select * from @TempTable
select datediff(ss,@t1,@t2) as timer

2 个答案:

答案 0 :(得分:2)

我的猜测是你的亚秒级选择是一个缓存的结果。而Insert @Tbl Select强制缓存刷新,因此在您需要的时间内,45秒更接近现实。此外,亚秒级选择意味着所有255万行都适合内存或部分缓存,并且您只返回sql开发人员副本中的前N个结果,因此允许应用程序进行分页。

答案 1 :(得分:-1)

@Tbl这样的表变量将查询执行限制为单个线程。更改代码以使用临时表。像这样:

select EPSName, count(*) as PlayCount, max(count(*)) OVER() AS MaxCount
into #Tbl
from LegalConfiguration l 
join Play p on p.LegalConfigNumber = l.SequenceNumber
where p.CurrentDate between @StartDate and @EndDate
group by EPSname

CREATE TABLE #Tbl (EPSName VARCHAR(100),PlayCount INT, MaxCount INT)

INSERT #Tbl
select EPSName, count(*) as PlayCount, max(count(*)) OVER() AS MaxCount
from LegalConfiguration l 
join Play p on p.LegalConfigNumber = l.SequenceNumber
where p.CurrentDate between @StartDate and @EndDate
group by EPSname

您也可以尝试在原始插入查询中添加OPTION(RECOMPILE)

here解释了并行性不适用于表变量的原因。这是文章的一个重要摘录:

编译查询时,既不填充表变量也不填充临时表,查询优化器假定“最小”行数,并且在SQL Server中始终为1。当SQL Server生成“估计”查询计划时,将使用此估计。虽然“估计”和“实际”查询计划在大多数情况下是相同的,但也有一些例外。如果在查询的同一批次中创建表(临时或永久),则SQL Serve必须重新编译查询,因为在第一次编译批处理时查询定义是未知的。表变量不是这种情况。