2009-06-08 14 views

答えて

5

データセットをループしないようにしてください。

複数の行を一度に挿入、更新、削除することができます。複数の行の挿入例をここに示します。

INSERT INTO YourTable 
     (col1, col2, col3, col4) 
    SELECT 
     cola, colb+Colz, colc, @X 
     FROM .... 
      LEFT OUTER JOIN ... 
     WHERE... 

ループを見ると、内部で何が行われたかを確認できます。挿入/削除/更新だけの場合は、単一のコマンドを使用するように書き換えます。 IFがある場合は、CASE文または挿入/削除/更新時のWHERE条件にすることができるかどうかを確認します。その場合は、ループを削除してsetコマンドを使用します。

私はループを取り、セットベースのコマンドに置き換え、実行時間を数分から数秒に減らしました。私は多くのネストされたループとプロシージャコールでプロシージャを実行し、ループを保持しました(挿入/削除/更新のみを使用することは不可能でした)が、カーソルを削除し、ロック/ブロッキングと大幅なパフォーマンスの向上も見られませんでした。ここではセットの上にカーソルがループよりも優れている2つのループ方法...

あなたがループしている場合は、このような何かです:

--this looks up each row for every iteration 
DECLARE @msg VARCHAR(250) 
DECLARE @hostname sysname 

--first select of currsor free loop 
SELECT @hostname= min(RTRIM(hostname)) 
    FROM master.dbo.sysprocesses (NOLOCK) 
    WHERE hostname <> '' 

WHILE @hostname is not null 
BEGIN 
    set @msg='exec master.dbo.xp_cmdshell "net send ' 
     + RTRIM(@hostname) + ' ' 
     + 'testing "' 
    print @msg 
    --EXEC (@msg) 

    --next select of cursor free loop 
    SELECT @hostname= min(RTRIM(hostname)) 
     FROM master.dbo.sysprocesses (NOLOCK) 
     WHERE hostname <> '' 
     and hostname > @hostname 
END 

あなたはアイテムの合理的なセット(ない100,000持っている場合)あなたがループすることができます:

--this will capture each Key to loop over 
DECLARE @msg VARCHAR(250) 
DECLARE @From int 
DECLARE @To  int 
CREATE TABLE #Rows 
(
    RowID  int not null primary key identity(1,1) 
    ,hostname varchar(100) 
) 

INSERT INTO #Rows 
SELECT DISTINCT hostname 
    FROM master.dbo.sysprocesses (NOLOCK) 
    WHERE hostname <> '' 
SELECT @From=0,@[email protected]@ROWCOUNT 

WHILE @From<@To 
BEGIN 
    SET @[email protected]+1 

    SELECT @msg='exec master.dbo.xp_cmdshell "net send ' 
     + RTRIM(hostname) + ' ' 
     + 'testing "' 
     FROM #Rows WHERE [email protected] 
    print @msg 
    --EXEC (@msg) 
END 
2

多くの場合、手続き型プログラミングに使用されるアプリケーション開発者は、習慣から逸脱します.SQLであっても手続き的にすべてを実行しようとします。

多くの場合、適切なパラメータを持つSELECTを使用することができます。または、UPDATE文を処理していることがあります。

ポイントは本当にあります:あなたは設定された操作で考え始める必要がありますし、RDBMSにあなたが何をしたいかを教えてください。

これに単一の「正しい」回答を与えるのは難しいです。具体的な例を示す必要がほとんどあります。

マーク

0

私は、特定の年に関連する財務データの合計を計算したコードを書いています。四半期ごとに、現在の四半期の値を実行中の合計に加算し、NULLを適切に処理して、前の四半期の実行中の合計が現在の四半期の値がNULLのときに引き継ぐようにしなければなりませんでした。

元はカーソルを使用してこれを行い、機能的な観点からはこれはビジネス要件を満たしていました。技術的な観点から見ると、データ量が増えるにつれてコードが指数関数的に長くなったため、これはショーストッパーとなりました。解決策は、カーソルを機能的要件を満たし、パフォーマンスの問題を排除した相関サブクエリで置き換えることでした。

これが役に立てば幸い、

ビル

4

私はWHILEループを持ついくつかのカーソルを交換しました。

DECLARE @SomeTable TABLE 
(
    ID int IDENTITY (1, 1) PRIMARY KEY NOT NULL, 
    SomeNumber int, 
    SomeText varchar 
) 

DECLARE @theCount int 
DECLARE @theMax int 

DECLARE @theNumber int 
DECLARE @theText varchar 

INSERT INTO @SomeTable (SomeNumber, SomeText) 
SELECT Number, Text 
FROM PrimaryTable 

SET @theCount = 1 
SELECT @theMax = COUNT(ID) FROM @SomeTable 

WHILE (@theCount <= @theMax) 
BEGIN 

    SET @theNumber = 0 
    SET @theText = '' 

    SELECT @theNumber = IsNull(Number, 0), @theText = IsNull(Text, 'nothing') 
    FROM @SomeTable 
    WHERE ID = @theCount 

    -- Do something. 
    PRINT 'This is ' + @theText + ' from record ' + CAST(@theNumber AS varchar) + '.' 

    SET @theCount = @theCount + 1 

END 

PRINT 'Done' 
関連する問題