我有一个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
答案 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必须重新编译查询,因为在第一次编译批处理时查询定义是未知的。表变量不是这种情况。