2016-10-27 6 views
0

私のSQLストアドプロシージャでパフォーマンスの問題が発生しています。主にカーソルが原因です。しかし、私はSQLストアドプロシージャのループを作るための別の方法について考えることはできません。今では、サーバーの複数のスレッドを使用して、プロシージャにパフォーマンスを向上させる方法がありますか?複数のスレッドを使用するストアドプロシージャ

は、ここに私のストアドプロシージャのための私のカーソルです:あなたはセットベースのソリューションを使用する必要があるときは、カーソルを使用している

DECLARE FILE_CURSOR CURSOR FOR 
    SELECT filenumber 
    FROM [fmsStage].[dbo].[file] 
    WHERE relationcode = @relationCode 

OPEN FILE_CURSOR 

FETCH NEXT FROM FILE_CURSOR INTO @fileID 

WHILE @@FETCH_STATUS = 0 
    BEGIN 
     /**** Fetch data from outgoinginvoiceline for RelationCode and FileNumber ****/ 
     SET @amount = (SELECT DISTINCT Sum(cnt) 
        FROM (SELECT Sum([fms].[dbo].[outgoinginvoiceline].[amount]) cnt 
          FROM [fms].[dbo].[outgoinginvoiceline] 
          WHERE [fms].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID) 
            AND [fms].[dbo].[outgoinginvoiceline].[relationcode] = @relationCode 
          UNION ALL 
          SELECT Sum([fmsAir].[dbo].[outgoinginvoiceline].[amount]) cnt 
          FROM [fmsAir].[dbo].[outgoinginvoiceline] 
          WHERE [fmsAir].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID) 
            AND [fmsAir].[dbo].[outgoinginvoiceline].[relationcode] = @relationCode 
          UNION ALL 
          SELECT Sum([fmsProjects].[dbo].[outgoinginvoiceline].[amount]) cnt 
          FROM [fmsProjects].[dbo].[outgoinginvoiceline] 
          WHERE [fmsProjects].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID) 
            AND [fmsProjects].[dbo].[outgoinginvoiceline].[relationcode] = @relationCode) AS counted) 
     /**** Get the currency from the database ****/ 
     SET @currency = (SELECT TOP 1 [fms].[dbo].[outgoinginvoiceline].[currency] 
         FROM [fms].[dbo].[outgoinginvoiceline] 
         WHERE [fms].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID) 
           AND [fms].[dbo].[outgoinginvoiceline].[relationcode] = @relationCode) 

     /**** If the currency is not EURO then use the currencyrate on it, by default the currencyrate is 1.00 ****/ 
     IF @currency != 'EUR' 
     BEGIN 
      SET @currencyRate = (SELECT TOP 1 [fms].[dbo].[outgoinginvoiceline].[rate] 
           FROM [fms].[dbo].[outgoinginvoiceline] 
           WHERE [fms].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID) 
             AND [fms].[dbo].[outgoinginvoiceline].[relationcode] = @relationCode) 
     END 

     /**** If @amount is NULL (empty) then we set it to zero because adding NULL creates issues ****/ 
     IF @amount IS NULL 
     BEGIN 
      SET @amount = 0 
     END 

     /**** Do the amount times currencyRate ****/ 
     SET @amount = @amount * @currencyRate 
     /**** Add the new amount to the total previous amount ****/ 
     SET @totalAmount = @totalAmount + @amount 
     /**** Fetch data from outgoinginvoiceline for RelationCode and FileNumber ****/ 
     SET @amount2 = (SELECT DISTINCT Sum(cnt) 
         FROM (SELECT Sum([fms].[dbo].[outgoinginvoiceline].[amount]) cnt 
           FROM [fms].[dbo].[outgoinginvoiceline] 
           WHERE [fms].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID) 
           UNION ALL 
           SELECT Sum([fmsAir].[dbo].[outgoinginvoiceline].[amount]) cnt 
           FROM [fmsAir].[dbo].[outgoinginvoiceline] 
           WHERE [fmsAir].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID) 
           UNION ALL 
           SELECT Sum([fmsProjects].[dbo].[outgoinginvoiceline].[amount]) cnt 
           FROM [fmsProjects].[dbo].[outgoinginvoiceline] 
           WHERE [fmsProjects].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID)) AS counted) 
     /**** Get the currency from the database ****/ 
     SET @currency2 = (SELECT TOP 1 [fms].[dbo].[outgoinginvoiceline].[currency] 
         FROM [fms].[dbo].[outgoinginvoiceline] 
         WHERE [fms].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID)) 

     /**** If the currency is not EURO then use the currencyrate on it, by default the currencyrate is 1.00 ****/ 
     IF @currency2 != 'EUR' 
     BEGIN 
      SET @currencyRate2 = (SELECT TOP 1 [fms].[dbo].[outgoinginvoiceline].[rate] 
            FROM [fms].[dbo].[outgoinginvoiceline] 
            WHERE [fms].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID)) 
     END 

     /**** If @amount is NULL (empty) then we set it to zero because adding NULL creates issues ****/ 
     IF @amount2 IS NULL 
     BEGIN 
      SET @amount2 = 0 
     END 

     /**** Do the amount times currencyRate ****/ 
     SET @amount2 = @amount2 * @currencyRate2 
     /**** Add the new amount to the total previous amount ****/ 
     SET @totalAmount2 = @totalAmount2 + @amount2 

     FETCH NEXT FROM FILE_CURSOR INTO @fileID 
    END 
+3

大部分の場合、カーソルを使用するのではなく、「セットベースのロジック」を使用して目的を達成する方法があります。まず、カーソルではなくSQLクエリーを使って何をしようとしているのかを再現しようとします。 – Jeremy

+0

あなたのような場合は、マルチスレッド化は役に立ちません。 Jeremyが指摘しているように、最良の方法は、あなたの問題に対するセットベースのアプローチを策定することです。 –

答えて

3

。それは、これはあなたのスキーマ/データを見ずに右であるかどうかをチェックするのは難しいですが

SELECT 
    fmsTotalAmount + fmsAirTotalAmount + fmsProjectsTotalAmount TotalAmount, 
    fmsRelationAmount + fmsAirRelationAmount + fmsProjectsRelationAmount TotalRelationAmount 
FROM (

    SELECT 
     SUM(
      CASE WHEN fms1.currency != 'EUR' 
       THEN fms1.Amount * fms1.Rate 
       ELSE ISNULL(fms1.Amount, 0) END) fmsTotalAmount, 
     SUM(
      CASE WHEN fms1.relationcode = @relationCode 
       THEN 
        CASE WHEN fms1.currency != 'EUR' 
         THEN fms1.Amount * fms1.Rate 
         ELSE ISNULL(fms1.Amount, 0) END 
       ELSE 0 END) fmsRelationAmount, 
     SUM(
      CASE WHEN fmsAir1.currency != 'EUR' 
       THEN fmsAir1.Amount * fmsAir1.Rate 
       ELSE ISNULL(fmsAir1.Amount, 0) END) fmsAirTotalAmount, 
     SUM(
      CASE WHEN fmsProjects1.relationcode = @relationCode 
       THEN 
        CASE WHEN fmsProjects1.currency != 'EUR' 
         THEN fmsProjects1.Amount * fmsAir1.Rate 
         ELSE ISNULL(fmsProjects1.Amount, 0) END 
       ELSE 0 END) fmsAirRelationAmount, 
     SUM(
      CASE WHEN fmsProjects1.currency != 'EUR' 
       THEN fmsProjects1.Amount * fmsAir1.Rate 
       ELSE ISNULL(fmsProjects1.Amount, 0) END) fmsProjectsTotalAmount, 
     SUM(
      CASE WHEN fmsProjects1.relationcode = @relationCode 
       THEN 
        CASE WHEN fmsProjects1.currency != 'EUR' 
         THEN fmsProjects1.Amount * fmsProjects1.Rate 
         ELSE ISNULL(fmsProjects1.Amount, 0) END 
       ELSE 0 END) fmsProjectsRelationAmount 
    FROM [fmsStage].[dbo].[file] f 
    LEFT JOIN [fms].[dbo].[outgoinginvoiceline] fms1 ON 
     fms1.filenumber = CONVERT(NVARCHAR, f.filenumber) 
    LEFT JOIN [fmsAir].[dbo].[outgoinginvoiceline] fmsAir1 ON 
     fmsAir1.filenumber = CONVERT(NVARCHAR, f.filenumber) 
    LEFT JOIN [fmsProjects].[dbo].[outgoinginvoiceline] fmsProjects1 ON 
     fmsProjects1.filenumber = CONVERT(NVARCHAR, f.filenumber) 
) a 

:セットベースのソリューションは次のようになります。これを理解するには

、ベーステーブルで最初に起動します。

SELECT * 
    FROM [fmsStage].[dbo].[file] f 
    LEFT JOIN [fms].[dbo].[outgoinginvoiceline] fms1 ON 
     fms1.filenumber = CONVERT(NVARCHAR, f.filenumber) 
    LEFT JOIN [fmsAir].[dbo].[outgoinginvoiceline] fmsAir1 ON 
     fmsAir1.filenumber = CONVERT(NVARCHAR, f.filenumber) 
    LEFT JOIN [fmsProjects].[dbo].[outgoinginvoiceline] fmsProjects1 ON 
     fmsProjects1.filenumber = CONVERT(NVARCHAR, f.filenumber) 

和が(これは、通貨変換を処理しません)かなり明白です:

SELECT SUM(ISNULL(fms1.Amount, 0)) fmsAmount, SUM(ISNULL(fmsAir1 .Amount, 0) fmsAirAmount --etc., etc. 
    FROM [fmsStage].[dbo].[file] f 
    LEFT JOIN [fms].[dbo].[outgoinginvoiceline] fms1 ON 
     fms1.filenumber = CONVERT(NVARCHAR, f.filenumber) 

はその後理解通貨換算およびリレーションコードによるフィルタリングを処理するcase文。

SELECT 
     fms1.Amount, 
     CASE WHEN fms1.currency != 'EUR' 
      THEN fms1.Amount * fms1.Rate 
      ELSE ISNULL(fms1.Amount, 0) END AmountValue, 
     CASE WHEN fms1.relationcode = @relationCode 
      THEN 
       CASE WHEN fms1.currency != 'EUR' 
        THEN fms1.Amount * fms1.Rate 
        ELSE ISNULL(fms1.Amount, 0) END 
      ELSE 0 END AmountValueOnlyIfSameRelation 
    FROM [fmsStage].[dbo].[file] f 
    LEFT JOIN [fms].[dbo].[outgoinginvoiceline] fms1 ON 
     fms1.filenumber = CONVERT(NVARCHAR, f.filenumber) 

それから、それをすべて一緒に組み合わせます。

+0

私はそれを見てそのハードを知っている、例のおかげで。私はこれを調べます –

+0

これはどういう仕組みか分かりませんが、それについての良い文書はありますか?私は2つのエラーが発生しています:1 'fmsRelationAmount'列が 'a'のために複数回指定されました2:無効な列名fmsProjectsRelationAmount –

+0

@ThimoFranken名前を置き換えることを忘れてしまいました。これは、SUMステートメントとSUMステートメントの組み合わせです。私もいくつかの説明を追加しました。しかし、これが正しいかどうかに頼らないで、シニアデベロッパーに確認し、それを手伝う必要があるかもしれません。 – mattmanser

関連する問題