0

我有一个 select 语句,它在 2.55 亿行的表上执行亚秒级。结果大约是 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
4

2 回答 2

2

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

于 2013-09-18T20:50:10.897 回答
-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)在原始插入查询中添加一个。

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

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

于 2013-09-18T21:04:39.653 回答