web-dev-qa-db-ja.com

NOCOUNTを使用したプロシージャのパフォーマンスの向上

特定のプロシージャのパフォーマンスを改善するために探しているので、SET NOCOUNT ONの挿入から始めたいと思いました。

この件に関する記事をいくつか読んだことがあります。

Aaron Bertrand

SET NOCOUNt ONはSQL Serverを改善しますSP Performance

しかし、私が本当に理解していないのは、これがプロシージャごとに1回必要かどうか、または「開始/終了」するたびに挿入する必要があるかどうかです。

たとえば、次の手順では、SET NOCOUNT ON権限を挿入して、最後の変数を設定する必要があります。set @PrintInfo = 'No Trip Number...

または、プロシージャのすべての「開始」の後にSET NOCOUNT ONを挿入する必要があります。

Create procedure [dbo].SSIS_UpdateDriveResults
(
@RSADriveID nvarchar (50),
@ProcedureID int,
@Registered int,
@Performed  int,
...
)
as 

set @ResultError = 0
set @ResultMessage = ''

declare @Id int
declare @Name varchar(64)
declare @DriveId int
declare @ErrorMessage nvarchar(255)
...

Set @ExternalIDs = cast(@RSADriveID as nvarchar(50))
set @IsFixedSite = 'N'
set @CurrentDate = getdate()
set @UpdateWho = -1
set @PrintInfo = ' No Trip Number   ' + convert(varchar(8), @RSADriveID, 1) 

select @UpdateWho = personid from db_name.[dbo].peoplelogindetail where loginid = 'RMADMIN'

if @UpdateWho <= 0
begin
set @ResultError = 1
set @ResultMessage = 'ERROR:Unable to locate employee with login RMADMIN for inserts. ' + @PrintInfo
print @ResultMessage
return
end


--Get the account or fixed site    
select top 1 @Id = a.accountid, @Name = a.name 
from db_name.[dbo].accounts a 
where a.accountid in
    (Select accountid from db_name.[dbo].drivemaster where deleted = 0 and statusid not in (5) and driveid in
        (select driveid from db_name.[dbo].DriveShiftDetail where ShiftID = (@RSADriveID))) --ShiftID

if(@Id is null or @Id <=0 )
begin
-- See if this is a fixed site
select @Id = dm.centerid, @Name = cd.desclong 
    from db_name.[dbo].drivemaster dm 
    join db_name.[dbo].centerdetail cd on dm.centerid = cd.centerid 
    where dm.deleted = 0 and dm.statusid not in (5) and dm.driveid in
        (select driveid from db_name.[dbo].DriveShiftDetail where ShiftID = (@RSADriveID)) --ShiftID

if(@Id > 0 )
begin
    set @IsFixedSite = 'Y'
end
end

-- Locate the drive
select
@DriveId = dm.driveid,
@DriveDate = dm.fromdatetime,
@Name=case when dm.drawid>0 then cd.desclong else a.name end

from db_name.[dbo].drivemaster dm
left outer join db_name.[dbo].accounts a on a.accountid=dm.accountid
left outer join db_name.[dbo].centerdetail cd on cd.centerid=dm.centerid
where dm.deleted = 0 and dm.statusid not in (5) and dm.driveid in
    (select driveid from db_name.[dbo].DriveShiftDetail where ShiftID = (@RSADriveID))

if(@DriveId is null or @DriveId <=0 )
begin
--For Historical Drives
select top 1 @DriveId = dm.driveid, @DriveDate = dm.fromdatetime, @Name=case when dm.drawid>0 then cd.desclong else a.name end, @ShiftID = dsd.ShiftID 
from db_name.[dbo].drivemaster dm
join db_name.[dbo].DriveShiftDetail dsd on dsd.DriveID=dm.DriveID
left outer join db_name.[dbo].accounts a on a.accountid=dm.accountid
left outer join db_name.[dbo].centerdetail cd on cd.centerid=dm.centerid

where dm.deleted = 0
and dm.statusid not in (5) 
and dm.externalid like @ExternalIds
and isnumeric(dm.ExternalID)=1

order by dsd.ShiftStart asc, dsd.ShiftID asc

if(@DriveId is null or @DriveId <=0 )
begin
    set @ResultError = 1
    set @ResultMessage = 'Unable to locate drive.' + @PrintInfo
    print @ResultMessage
    return
end
end
set @PrintInfo = '  Trip Number:( ' + convert(varchar(8), @RSADriveID, 1) + ' )  Name: ' + @Name
set @PrintInfo = @PrintInfo + '  Date: ' + convert(varchar(10), @DriveDate, 101)

...

if not exists (select * from db_name.[dbo].DriveShiftActualDetail where ShiftID=@ShiftId)
begin
--Insert Missing DriveShiftActualDetail Rows
INSERT INTO db_name.[dbo].DriveShiftActualDetail
    (ShiftID,FirstTimeDonors,Registered,Voids,QNS,Deferrals,Collected,Contaminated,Cancellations,TurnAways,WalkIns,SelfDeferrals,NoShows,ShiftStart,
    ShiftEnd,HadLunch,LunchStart,LunchEnd,ActualStaff,SignupReduction,UpdateWho,UpdateWhen,UniqueKey,DonorsScheduled,MildReactions,ModReactions,SevReactions)

select
    dsd.ShiftID,0,0,0,0,0,0,0,0,0,0,0,0,dsd.ShiftStart,dsd.ShiftEnd,dsd.HasLunch,dsd.LunchStart,dsd.LunchEnd,
    isnull((select count(distinct personid) from db_name.[dbo].peoplestaffingdetail where shiftid in (select shiftid from db_name.[dbo].staffingeventshiftdetail where driveshiftid=dsd.ShiftID)),0),
    dsd.SignupReduction,dbo.HemasphereUserNo(),getdate(),newid(),dsd.DonorsScheduled,0,0,0

from db_name.[dbo].DriveShiftDetail dsd

where not exists
(
    select dsad.* from db_name.[dbo].DriveShiftActualDetail dsad where dsad.shiftid=dsd.shiftid
)
and dsd.ShiftID=@ShiftId

if(@@Error <> 0)
begin
    select @ErrorMessage = description from master.dbo.sysmessages where error = @@Error
    set @ResultError = 1
    set @ResultMessage = 'ERROR:Error Inserting the Drive Shift Actual record. ' + @PrintInfo
end 
end
4
MISNole

SET NOCOUNT ON;プロシージャごとに1回、できればプロシージャ自体の上部に配置します。確かに、出力を生成するステートメントの前にそれが必要です。

したがって、たとえば、プロシージャを作成するためのテンプレートとして次のようなものを使用します。

CREATE PROCEDURE dbo.MyProc
AS
BEGIN
    SET NOCOUNT ON;
    ....
END
GO

Books Online はこれについてSET NOCOUNT ON

Transact-SQLステートメントまたはストアドプロシージャの影響を受ける行数のカウントを示すメッセージが、結果セットの一部として返されないようにします。

SET NOCOUNT ONは、ストアード・プロシージャー内のステートメントごとにDONE_IN_PROCメッセージがクライアントに送信されるのを防ぎます。実際のデータをほとんど返さないいくつかのステートメントを含むストアドプロシージャ、またはTransact-SQLループを含むプロシージャの場合、SET NOCOUNTをONに設定すると、ネットワークトラフィックが大幅に削減されるため、パフォーマンスが大幅に向上します。

上記で概説したように、このオプションをプロシージャ本体の最初に設定すると、ステートメントが実際にプロシージャ内にあることを簡単に確認できます。

行カウント機能は、実行されたDMLが成功したかどうかを確認するために、特定のソフトウェア(特にリンクサーバー用のSQL Server自体)で使用されていることに注意してください。設定NOCOUNT ONは、予期しないエラーを発生させる可能性があり、トラブルシューティングが困難な場合があります。また、以下のコメントと @ AaronBertrand からのアドバイスにも注意してください。

心に留めておくべきことの1つ(およびNOCOUNTを推奨する場合は常に免責事項)は、特定のテクノロジに干渉する可能性があることです。たとえば、古いADOコード(ASP.NETより前)がある場合)は、DONE_IN_PROCメッセージを独立した結果セットとして解釈するため、既存のコードにはrs.nextRecordSet()などのコードがすでに含まれている可能性があります。また、Entity Frameworkの特定のモジュール(およびおそらく他のORM)は、これらのメッセージに依存してDML操作の成功を判断します。したがって、これらのテクノロジーを使用し、すでに機能しているコードがある場合は、それらをすべてのコードに盲目的に追加しないでください。

9
Max Vernon