Dies ist mein Test unter SQL Server 2012 RTM.
if object_id('tempdb..#temp1') is not null drop table #temp1;
if object_id('tempdb..#timer') is not null drop table #timer;
if object_id('tempdb..#bigtimer') is not null drop table #bigtimer;
GO
select a.*
into #temp1
from master..spt_values a
join master..spt_values b on b.type='p' and b.number < 1000;
alter table #temp1 add id int identity(10,20) primary key clustered;
create table #timer (
id int identity primary key,
which bit not null,
started datetime2 not null,
completed datetime2 not null,
);
create table #bigtimer (
id int identity primary key,
which bit not null,
started datetime2 not null,
completed datetime2 not null,
);
GO
--set ansi_warnings on;
set nocount on;
dbcc dropcleanbuffers with NO_INFOMSGS;
dbcc freeproccache with NO_INFOMSGS;
declare @bigstart datetime2;
declare @start datetime2, @dump bigint, @counter int;
set @bigstart = sysdatetime();
set @counter = 1;
while @counter <= 100
begin
set @start = sysdatetime();
select @dump = count(case when number < 100 then 1 end) from #temp1;
insert #timer values (0, @start, sysdatetime());
set @counter += 1;
end;
insert #bigtimer values (0, @bigstart, sysdatetime());
set nocount off;
GO
set nocount on;
dbcc dropcleanbuffers with NO_INFOMSGS;
dbcc freeproccache with NO_INFOMSGS;
declare @bigstart datetime2;
declare @start datetime2, @dump bigint, @counter int;
set @bigstart = sysdatetime();
set @counter = 1;
while @counter <= 100
begin
set @start = sysdatetime();
select @dump = SUM(case when number < 100 then 1 else 0 end) from #temp1;
insert #timer values (1, @start, sysdatetime());
set @counter += 1;
end;
insert #bigtimer values (1, @bigstart, sysdatetime());
set nocount off;
GO
Einzelne Läufe und Chargen getrennt betrachten
select which, min(datediff(mcs, started, completed)), max(datediff(mcs, started, completed)),
avg(datediff(mcs, started, completed))
from #timer group by which
select which, min(datediff(mcs, started, completed)), max(datediff(mcs, started, completed)),
avg(datediff(mcs, started, completed))
from #bigtimer group by which
Die Ergebnisse nach 5-maligem Ausführen (und Wiederholen) sind ziemlich nicht schlüssig.
which ** Individual
----- ----------- ----------- -----------
0 93600 187201 103927
1 93600 187201 103864
which ** Batch
----- ----------- ----------- -----------
0 10108817 10545619 10398978
1 10327219 10498818 10386498
Es zeigt, dass die Ausführungsbedingungen weitaus variabler sind als die Implementierung, gemessen an der Granularität des SQL Server-Timers. Beide Versionen können die Oberhand gewinnen, und die maximale Varianz, die ich je hatte, beträgt 2,5%.
Ein anderer Ansatz:
set showplan_text on;
GO
select SUM(case when number < 100 then 1 else 0 end) from #temp1;
select count(case when number < 100 then 1 end) from #temp1;
StmtText (SUM)
|--Compute Scalar(DEFINE:([Expr1003]=CASE WHEN [Expr1011]=(0) THEN NULL ELSE [Expr1012] END))
|--Stream Aggregate(DEFINE:([Expr1011]=Count(*), [Expr1012]=SUM([Expr1004])))
|--Compute Scalar(DEFINE:([Expr1004]=CASE WHEN [tempdb].[dbo].[#temp1].[number]<(100) THEN (1) ELSE (0) END))
|--Clustered Index Scan(OBJECT:([tempdb].[dbo].[#temp1]))
StmtText (COUNT)
|--Compute Scalar(DEFINE:([Expr1003]=CONVERT_IMPLICIT(int,[Expr1008],0)))
|--Stream Aggregate(DEFINE:([Expr1008]=COUNT([Expr1004])))
|--Compute Scalar(DEFINE:([Expr1004]=CASE WHEN [tempdb].[dbo].[#temp1].[number]<(100) THEN (1) ELSE NULL END))
|--Clustered Index Scan(OBJECT:([tempdb].[dbo].[#temp1]))
Meiner Lektüre nach scheint die SUM-Version etwas mehr zu leisten. Sie führt zusätzlich zu einer SUMME eine COUNT durch . Having said that, ist COUNT(*)
anders und sollte schneller sein als COUNT([Expr1004])
(überspringen NULLs, mehr Logik). Ein vernünftiger Optimierer wird erkennen, dass [Expr1004]
in SUM([Expr1004])
der SUM-Version ein "int" -Typ vorliegt und daher ein Ganzzahlregister verwendet wird.
Auf jeden Fall, obwohl ich immer noch glaube, dass die COUNT
Version in den meisten RDBMS schneller sein wird, ist meine Schlussfolgerung aus den Tests, dass ich SUM(.. 1.. 0..)
in Zukunft damit umgehen werde, zumindest für SQL Server aus keinem anderen Grund als den ANSI-WARNUNGEN, die bei der Verwendung ausgegeben werden COUNT
.